aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Davidson <colrdavidson@gmail.com>2024-09-24 02:32:06 -0700
committerColin Davidson <colrdavidson@gmail.com>2024-09-24 02:32:06 -0700
commitf3ab14b8ccb45d0fef8a96937635bdf0943ce7d6 (patch)
tree1309d7c797117463996a84522ef3d1c9713a286c
parent99938c7d4fb26d43a07dd4b8f4f00ab87e67e73f (diff)
parentf7d74ff3a8596efef67d151ffb758ed085e94be0 (diff)
Merge branch 'master' into macharena
-rw-r--r--.github/workflows/ci.yml42
-rw-r--r--.github/workflows/nightly.yml145
-rw-r--r--base/intrinsics/intrinsics.odin4
-rw-r--r--base/runtime/core.odin31
-rw-r--r--base/runtime/core_builtin.odin24
-rw-r--r--base/runtime/core_builtin_soa.odin16
-rw-r--r--base/runtime/default_allocators_nil.odin4
-rw-r--r--base/runtime/entry_unix.odin6
-rw-r--r--base/runtime/entry_wasm.odin6
-rw-r--r--base/runtime/entry_windows.odin6
-rw-r--r--base/runtime/heap_allocator.odin22
-rw-r--r--base/runtime/heap_allocator_orca.odin4
-rw-r--r--base/runtime/heap_allocator_other.odin4
-rw-r--r--base/runtime/heap_allocator_unix.odin4
-rw-r--r--base/runtime/internal.odin13
-rw-r--r--base/runtime/os_specific_bsd.odin4
-rw-r--r--base/runtime/os_specific_darwin.odin4
-rw-r--r--base/runtime/os_specific_freestanding.odin4
-rw-r--r--base/runtime/os_specific_haiku.odin4
-rw-r--r--base/runtime/os_specific_js.odin4
-rw-r--r--base/runtime/os_specific_linux.odin2
-rw-r--r--base/runtime/os_specific_orca.odin4
-rw-r--r--base/runtime/os_specific_wasi.odin4
-rw-r--r--base/runtime/os_specific_windows.odin4
-rw-r--r--base/runtime/procs_darwin.odin2
-rw-r--r--base/runtime/procs_js.odin2
-rw-r--r--base/runtime/procs_wasm.odin62
-rw-r--r--base/runtime/procs_windows_amd64.odin4
-rw-r--r--base/runtime/procs_windows_i386.odin4
-rw-r--r--base/runtime/thread_management.odin34
-rw-r--r--base/runtime/wasm_allocator.odin2
-rwxr-xr-xci/build_linux_static.sh19
-rw-r--r--ci/nightly.py43
-rw-r--r--core/bytes/buffer.odin36
-rw-r--r--core/bytes/bytes.odin12
-rw-r--r--core/bytes/reader.odin11
-rw-r--r--core/c/libc/errno.odin8
-rw-r--r--core/c/libc/stdio.odin26
-rw-r--r--core/c/libc/stdlib.odin10
-rw-r--r--core/c/libc/string.odin1
-rw-r--r--core/c/libc/time.odin4
-rw-r--r--core/c/libc/wctype.odin2
-rw-r--r--core/compress/gzip/doc.odin90
-rw-r--r--core/compress/gzip/example.odin89
-rw-r--r--core/compress/shoco/model.odin3
-rw-r--r--core/compress/shoco/shoco.odin4
-rw-r--r--core/compress/zlib/doc.odin50
-rw-r--r--core/compress/zlib/example.odin47
-rw-r--r--core/compress/zlib/zlib.odin2
-rw-r--r--core/container/bit_array/bit_array.odin74
-rw-r--r--core/container/bit_array/doc.odin8
-rw-r--r--core/container/intrusive/list/doc.odin15
-rw-r--r--core/container/small_array/small_array.odin10
-rw-r--r--core/crypto/_aes/hw_intel/api.odin2
-rw-r--r--core/crypto/_aes/hw_intel/ghash.odin2
-rw-r--r--core/crypto/_aes/hw_intel/hw_intel_keysched.odin2
-rw-r--r--core/crypto/_chacha20/simd256/chacha20_simd256.odin2
-rw-r--r--core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin2
-rw-r--r--core/crypto/aead/doc.odin87
-rw-r--r--core/crypto/aes/aes.odin6
-rw-r--r--core/crypto/aes/aes_ctr_hw_intel.odin2
-rw-r--r--core/crypto/aes/aes_ecb_hw_intel.odin2
-rw-r--r--core/crypto/aes/aes_gcm_hw_intel.odin2
-rw-r--r--core/crypto/aes/aes_impl_hw_gen.odin2
-rw-r--r--core/crypto/aes/aes_impl_hw_intel.odin2
-rw-r--r--core/crypto/blake2b/blake2b.odin4
-rw-r--r--core/crypto/blake2s/blake2s.odin4
-rw-r--r--core/crypto/chacha20/chacha20.odin4
-rw-r--r--core/crypto/chacha20poly1305/chacha20poly1305.odin4
-rw-r--r--core/crypto/ed25519/ed25519.odin6
-rw-r--r--core/crypto/hash/doc.odin58
-rw-r--r--core/crypto/hash/hash.odin42
-rw-r--r--core/crypto/hash/hash_freestanding.odin10
-rw-r--r--core/crypto/hash/hash_os.odin38
-rw-r--r--core/crypto/hkdf/hkdf.odin2
-rw-r--r--core/crypto/hmac/hmac.odin2
-rw-r--r--core/crypto/kmac/kmac.odin2
-rw-r--r--core/crypto/legacy/md5/md5.odin4
-rw-r--r--core/crypto/legacy/sha1/sha1.odin6
-rw-r--r--core/crypto/pbkdf2/pbkdf2.odin2
-rw-r--r--core/crypto/poly1305/poly1305.odin2
-rw-r--r--core/crypto/rand_bsd.odin2
-rw-r--r--core/crypto/rand_generic.odin14
-rw-r--r--core/crypto/ristretto255/ristretto255.odin2
-rw-r--r--core/crypto/sha2/sha2.odin4
-rw-r--r--core/crypto/sha3/sha3.odin2
-rw-r--r--core/crypto/shake/shake.odin4
-rw-r--r--core/crypto/siphash/siphash.odin13
-rw-r--r--core/crypto/sm3/sm3.odin2
-rw-r--r--core/crypto/tuplehash/tuplehash.odin2
-rw-r--r--core/crypto/x25519/x25519.odin2
-rw-r--r--core/debug/trace/trace_cpp.odin4
-rw-r--r--core/debug/trace/trace_nil.odin4
-rw-r--r--core/debug/trace/trace_windows.odin4
-rw-r--r--core/dynlib/doc.odin3
-rw-r--r--core/dynlib/lib_js.odin4
-rw-r--r--core/dynlib/lib_unix.odin4
-rw-r--r--core/dynlib/lib_windows.odin4
-rw-r--r--core/encoding/ansi/doc.odin6
-rw-r--r--core/encoding/cbor/unmarshal.odin38
-rw-r--r--core/encoding/csv/doc.odin96
-rw-r--r--core/encoding/csv/example.odin88
-rw-r--r--core/encoding/csv/reader.odin4
-rw-r--r--core/encoding/endian/doc.odin25
-rw-r--r--core/encoding/entity/entity.odin26
-rw-r--r--core/encoding/entity/generated.odin2
-rw-r--r--core/encoding/hxa/doc.odin172
-rw-r--r--core/encoding/json/unmarshal.odin25
-rw-r--r--core/encoding/uuid/doc.odin9
-rw-r--r--core/encoding/uuid/writing.odin35
-rw-r--r--core/encoding/varint/doc.odin13
-rw-r--r--core/encoding/varint/leb128.odin4
-rw-r--r--core/encoding/xml/doc.odin23
-rw-r--r--core/encoding/xml/xml_reader.odin28
-rw-r--r--core/flags/doc.odin40
-rw-r--r--core/flags/errors_bsd.odin2
-rw-r--r--core/flags/errors_nonbsd.odin3
-rw-r--r--core/flags/internal_assignment.odin8
-rw-r--r--core/flags/internal_parsing.odin2
-rw-r--r--core/flags/internal_rtti.odin2
-rw-r--r--core/flags/internal_rtti_nonbsd.odin5
-rw-r--r--core/flags/internal_validation.odin2
-rw-r--r--core/fmt/example.odin2
-rw-r--r--core/fmt/fmt_js.odin2
-rw-r--r--core/fmt/fmt_os.odin6
-rw-r--r--core/hash/xxhash/common.odin3
-rw-r--r--core/hash/xxhash/streaming.odin3
-rw-r--r--core/hash/xxhash/xxhash_3.odin1
-rw-r--r--core/hash/xxhash/xxhash_32.odin1
-rw-r--r--core/hash/xxhash/xxhash_64.odin19
-rw-r--r--core/image/bmp/bmp_js.odin2
-rw-r--r--core/image/bmp/bmp_os.odin2
-rw-r--r--core/image/common.odin2
-rw-r--r--core/image/general_js.odin2
-rw-r--r--core/image/general_os.odin2
-rw-r--r--core/image/netpbm/netpbm.odin2
-rw-r--r--core/image/netpbm/netpbm_js.odin2
-rw-r--r--core/image/netpbm/netpbm_os.odin2
-rw-r--r--core/image/png/doc.odin348
-rw-r--r--core/image/png/example.odin351
-rw-r--r--core/image/png/helpers.odin1
-rw-r--r--core/image/png/png.odin7
-rw-r--r--core/image/png/png_js.odin2
-rw-r--r--core/image/png/png_os.odin2
-rw-r--r--core/image/qoi/qoi.odin2
-rw-r--r--core/image/qoi/qoi_js.odin2
-rw-r--r--core/image/qoi/qoi_os.odin2
-rw-r--r--core/image/tga/tga_js.odin2
-rw-r--r--core/image/tga/tga_os.odin2
-rw-r--r--core/io/util.odin14
-rw-r--r--core/log/file_console_logger.odin4
-rw-r--r--core/math/big/common.odin2
-rw-r--r--core/math/big/tune.odin2
-rw-r--r--core/math/linalg/glsl/linalg_glsl.odin70
-rw-r--r--core/math/linalg/hlsl/linalg_hlsl.odin148
-rw-r--r--core/math/math.odin12
-rw-r--r--core/math/math_basic.odin2
-rw-r--r--core/math/math_basic_js.odin2
-rw-r--r--core/math/noise/internal.odin2
-rw-r--r--core/math/noise/opensimplex2.odin6
-rw-r--r--core/mem/alloc.odin1006
-rw-r--r--core/mem/allocators.odin2322
-rw-r--r--core/mem/doc.odin126
-rw-r--r--core/mem/mem.odin485
-rw-r--r--core/mem/mutex_allocator.odin29
-rw-r--r--core/mem/raw.odin96
-rw-r--r--core/mem/rollback_stack_allocator.odin347
-rw-r--r--core/mem/tracking_allocator.odin121
-rw-r--r--core/mem/virtual/arena.odin4
-rw-r--r--core/mem/virtual/virtual.odin5
-rw-r--r--core/mem/virtual/virtual_linux.odin4
-rw-r--r--core/mem/virtual/virtual_other.odin14
-rw-r--r--core/mem/virtual/virtual_platform.odin2
-rw-r--r--core/mem/virtual/virtual_posix.odin10
-rw-r--r--core/mem/virtual/virtual_windows.odin4
-rw-r--r--core/net/addr.odin2
-rw-r--r--core/net/common.odin2
-rw-r--r--core/net/dns.odin2
-rw-r--r--core/net/dns_unix.odin2
-rw-r--r--core/net/dns_windows.odin34
-rw-r--r--core/net/doc.odin62
-rw-r--r--core/net/errors_darwin.odin2
-rw-r--r--core/net/errors_freebsd.odin2
-rw-r--r--core/net/errors_linux.odin2
-rw-r--r--core/net/errors_windows.odin2
-rw-r--r--core/net/interface.odin2
-rw-r--r--core/net/interface_darwin.odin2
-rw-r--r--core/net/interface_freebsd.odin2
-rw-r--r--core/net/interface_linux.odin2
-rw-r--r--core/net/interface_windows.odin2
-rw-r--r--core/net/socket.odin9
-rw-r--r--core/net/socket_darwin.odin16
-rw-r--r--core/net/socket_freebsd.odin16
-rw-r--r--core/net/socket_linux.odin15
-rw-r--r--core/net/socket_windows.odin17
-rw-r--r--core/odin/ast/ast.odin3
-rw-r--r--core/odin/parser/file_tags.odin258
-rw-r--r--core/odin/parser/parse_files.odin4
-rw-r--r--core/odin/parser/parser.odin48
-rw-r--r--core/odin/tokenizer/token.odin2
-rw-r--r--core/odin/tokenizer/tokenizer.odin20
-rw-r--r--core/os/dir_unix.odin2
-rw-r--r--core/os/file_windows.odin30
-rw-r--r--core/os/os2/allocators.odin14
-rw-r--r--core/os/os2/dir_linux.odin2
-rw-r--r--core/os/os2/dir_posix.odin4
-rw-r--r--core/os/os2/dir_windows.odin2
-rw-r--r--core/os/os2/env_linux.odin2
-rw-r--r--core/os/os2/env_posix.odin4
-rw-r--r--core/os/os2/env_windows.odin2
-rw-r--r--core/os/os2/errors_linux.odin10
-rw-r--r--core/os/os2/errors_posix.odin4
-rw-r--r--core/os/os2/errors_windows.odin5
-rw-r--r--core/os/os2/file.odin6
-rw-r--r--core/os/os2/file_linux.odin24
-rw-r--r--core/os/os2/file_posix.odin21
-rw-r--r--core/os/os2/file_posix_darwin.odin2
-rw-r--r--core/os/os2/file_posix_freebsd.odin2
-rw-r--r--core/os/os2/file_posix_netbsd.odin2
-rw-r--r--core/os/os2/file_posix_other.odin4
-rw-r--r--core/os/os2/file_util.odin3
-rw-r--r--core/os/os2/file_windows.odin24
-rw-r--r--core/os/os2/heap_linux.odin62
-rw-r--r--core/os/os2/heap_posix.odin4
-rw-r--r--core/os/os2/heap_windows.odin2
-rw-r--r--core/os/os2/internal_util.odin2
-rw-r--r--core/os/os2/path_linux.odin2
-rw-r--r--core/os/os2/path_posix.odin14
-rw-r--r--core/os/os2/path_windows.odin2
-rw-r--r--core/os/os2/pipe_linux.odin2
-rw-r--r--core/os/os2/pipe_posix.odin4
-rw-r--r--core/os/os2/pipe_windows.odin2
-rw-r--r--core/os/os2/process.odin27
-rw-r--r--core/os/os2/process_linux.odin20
-rw-r--r--core/os/os2/process_posix.odin23
-rw-r--r--core/os/os2/process_posix_darwin.odin2
-rw-r--r--core/os/os2/process_posix_other.odin4
-rw-r--r--core/os/os2/process_windows.odin224
-rw-r--r--core/os/os2/stat_linux.odin2
-rw-r--r--core/os/os2/stat_posix.odin4
-rw-r--r--core/os/os2/stat_windows.odin2
-rw-r--r--core/os/os2/temp_file_linux.odin2
-rw-r--r--core/os/os2/temp_file_posix.odin4
-rw-r--r--core/os/os2/temp_file_windows.odin2
-rw-r--r--core/os/os2/user.odin16
-rw-r--r--core/os/os_darwin.odin18
-rw-r--r--core/os/os_freebsd.odin51
-rw-r--r--core/os/os_freestanding.odin2
-rw-r--r--core/os/os_haiku.odin139
-rw-r--r--core/os/os_js.odin91
-rw-r--r--core/os/os_linux.odin25
-rw-r--r--core/os/os_netbsd.odin58
-rw-r--r--core/os/os_openbsd.odin144
-rw-r--r--core/os/os_windows.odin6
-rw-r--r--core/os/stat_unix.odin2
-rw-r--r--core/os/stream.odin15
-rw-r--r--core/path/filepath/path_unix.odin2
-rw-r--r--core/prof/spall/doc.odin3
-rw-r--r--core/prof/spall/spall_linux.odin4
-rw-r--r--core/prof/spall/spall_unix.odin4
-rw-r--r--core/prof/spall/spall_windows.odin4
-rw-r--r--core/reflect/iterator.odin7
-rw-r--r--core/reflect/reflect.odin70
-rw-r--r--core/simd/x86/abm.odin2
-rw-r--r--core/simd/x86/adx.odin2
-rw-r--r--core/simd/x86/aes.odin2
-rw-r--r--core/simd/x86/cmpxchg16b.odin2
-rw-r--r--core/simd/x86/fxsr.odin2
-rw-r--r--core/simd/x86/pclmulqdq.odin2
-rw-r--r--core/simd/x86/rdtsc.odin2
-rw-r--r--core/simd/x86/sha.odin2
-rw-r--r--core/simd/x86/sse.odin2
-rw-r--r--core/simd/x86/sse2.odin2
-rw-r--r--core/simd/x86/sse3.odin2
-rw-r--r--core/simd/x86/sse41.odin2
-rw-r--r--core/simd/x86/sse42.odin2
-rw-r--r--core/simd/x86/ssse3.odin2
-rw-r--r--core/simd/x86/types.odin2
-rw-r--r--core/slice/slice.odin11
-rw-r--r--core/slice/sort_private.odin2
-rw-r--r--core/strconv/strconv.odin62
-rw-r--r--core/strings/strings.odin212
-rw-r--r--core/sync/chan/chan.odin90
-rw-r--r--core/sync/doc.odin6
-rw-r--r--core/sync/extended.odin75
-rw-r--r--core/sync/futex_darwin.odin29
-rw-r--r--core/sync/futex_freebsd.odin12
-rw-r--r--core/sync/futex_haiku.odin2
-rw-r--r--core/sync/futex_linux.odin12
-rw-r--r--core/sync/futex_netbsd.odin10
-rw-r--r--core/sync/futex_openbsd.odin12
-rw-r--r--core/sync/futex_wasm.odin12
-rw-r--r--core/sync/futex_windows.odin4
-rw-r--r--core/sync/primitives.odin20
-rw-r--r--core/sync/primitives_atomic.odin6
-rw-r--r--core/sync/primitives_darwin.odin4
-rw-r--r--core/sync/primitives_freebsd.odin4
-rw-r--r--core/sync/primitives_haiku.odin2
-rw-r--r--core/sync/primitives_internal.odin2
-rw-r--r--core/sync/primitives_linux.odin4
-rw-r--r--core/sync/primitives_netbsd.odin2
-rw-r--r--core/sync/primitives_openbsd.odin4
-rw-r--r--core/sync/primitives_wasm.odin4
-rw-r--r--core/sync/primitives_windows.odin4
-rw-r--r--core/sys/darwin/CoreFoundation/CFString.odin299
-rw-r--r--core/sys/darwin/Foundation/NSApplication.odin5
-rw-r--r--core/sys/darwin/Foundation/NSEvent.odin4
-rw-r--r--core/sys/darwin/Foundation/NSString.odin5
-rw-r--r--core/sys/darwin/Foundation/objc.odin113
-rw-r--r--core/sys/darwin/darwin.odin2
-rw-r--r--core/sys/darwin/sync.odin11
-rw-r--r--core/sys/darwin/xnu_system_call_helpers.odin6
-rw-r--r--core/sys/darwin/xnu_system_call_wrappers.odin58
-rw-r--r--core/sys/freebsd/syscalls.odin108
-rw-r--r--core/sys/freebsd/types.odin12
-rw-r--r--core/sys/haiku/errors.odin2
-rw-r--r--core/sys/haiku/find_directory.odin2
-rw-r--r--core/sys/haiku/os.odin2
-rw-r--r--core/sys/haiku/types.odin2
-rw-r--r--core/sys/info/cpu_arm.odin2
-rw-r--r--core/sys/info/cpu_intel.odin2
-rw-r--r--core/sys/info/cpu_linux_arm.odin4
-rw-r--r--core/sys/info/cpu_linux_riscv64.odin125
-rw-r--r--core/sys/info/cpu_riscv64.odin98
-rw-r--r--core/sys/info/doc.odin9
-rw-r--r--core/sys/info/platform_bsd.odin2
-rw-r--r--core/sys/info/platform_darwin.odin4
-rw-r--r--core/sys/kqueue/kqueue.odin2
-rw-r--r--core/sys/linux/bits.odin84
-rw-r--r--core/sys/linux/helpers.odin4
-rw-r--r--core/sys/linux/sys.odin46
-rw-r--r--core/sys/linux/syscall_amd64.odin2
-rw-r--r--core/sys/linux/syscall_arm32.odin2
-rw-r--r--core/sys/linux/syscall_arm64.odin2
-rw-r--r--core/sys/linux/syscall_i386.odin2
-rw-r--r--core/sys/linux/syscall_riscv64.odin3
-rw-r--r--core/sys/linux/types.odin17
-rw-r--r--core/sys/linux/wrappers.odin2
-rw-r--r--core/sys/llvm/bit_manipulation.odin1
-rw-r--r--core/sys/llvm/code_generator.odin1
-rw-r--r--core/sys/llvm/standard_c_library.odin1
-rw-r--r--core/sys/posix/time.odin2
-rw-r--r--core/sys/posix/unistd.odin2
-rw-r--r--core/sys/unix/pthread_darwin.odin2
-rw-r--r--core/sys/unix/pthread_freebsd.odin2
-rw-r--r--core/sys/unix/pthread_linux.odin2
-rw-r--r--core/sys/unix/pthread_openbsd.odin2
-rw-r--r--core/sys/unix/pthread_unix.odin4
-rw-r--r--core/sys/unix/sysctl_darwin.odin2
-rw-r--r--core/sys/unix/sysctl_freebsd.odin2
-rw-r--r--core/sys/unix/sysctl_openbsd.odin2
-rw-r--r--core/sys/valgrind/callgrind.odin2
-rw-r--r--core/sys/valgrind/helgrind.odin2
-rw-r--r--core/sys/valgrind/memcheck.odin2
-rw-r--r--core/sys/valgrind/valgrind.odin2
-rw-r--r--core/sys/wasm/README.md15
-rw-r--r--core/sys/wasm/js/dom.odin (renamed from vendor/wasm/js/dom.odin)21
-rw-r--r--core/sys/wasm/js/dom_all_targets.odin (renamed from vendor/wasm/js/dom_all_targets.odin)2
-rw-r--r--core/sys/wasm/js/events.odin (renamed from vendor/wasm/js/events.odin)75
-rw-r--r--core/sys/wasm/js/events_all_targets.odin (renamed from vendor/wasm/js/events_all_targets.odin)5
-rw-r--r--core/sys/wasm/js/general.odin (renamed from vendor/wasm/js/general.odin)2
-rw-r--r--core/sys/wasm/js/memory_all_targets.odin (renamed from vendor/wasm/js/memory_all_targets.odin)2
-rw-r--r--core/sys/wasm/js/memory_js.odin (renamed from vendor/wasm/js/memory_js.odin)2
-rw-r--r--core/sys/wasm/js/odin.js (renamed from vendor/wasm/js/runtime.js)263
-rw-r--r--core/sys/wasm/wasi/wasi_api.odin2
-rw-r--r--core/sys/windows/advapi32.odin2
-rw-r--r--core/sys/windows/bcrypt.odin2
-rw-r--r--core/sys/windows/bluetooth.odin2
-rw-r--r--core/sys/windows/codepage.odin2
-rw-r--r--core/sys/windows/comctl32.odin2
-rw-r--r--core/sys/windows/comdlg32.odin2
-rw-r--r--core/sys/windows/dbghelp.odin2
-rw-r--r--core/sys/windows/dnsapi.odin2
-rw-r--r--core/sys/windows/dwmapi.odin6
-rw-r--r--core/sys/windows/gdi32.odin2
-rw-r--r--core/sys/windows/hidpi.odin2
-rw-r--r--core/sys/windows/hidusage.odin2
-rw-r--r--core/sys/windows/ip_helper.odin2
-rw-r--r--core/sys/windows/kernel32.odin21
-rw-r--r--core/sys/windows/key_codes.odin2
-rw-r--r--core/sys/windows/known_folders.odin2
-rw-r--r--core/sys/windows/netapi32.odin2
-rw-r--r--core/sys/windows/ntdll.odin2
-rw-r--r--core/sys/windows/shcore.odin2
-rw-r--r--core/sys/windows/shell32.odin2
-rw-r--r--core/sys/windows/shlwapi.odin2
-rw-r--r--core/sys/windows/synchronization.odin2
-rw-r--r--core/sys/windows/system_params.odin2
-rw-r--r--core/sys/windows/tlhelp.odin2
-rw-r--r--core/sys/windows/types.odin52
-rw-r--r--core/sys/windows/user32.odin41
-rw-r--r--core/sys/windows/userenv.odin2
-rw-r--r--core/sys/windows/util.odin2
-rw-r--r--core/sys/windows/ux_theme.odin2
-rw-r--r--core/sys/windows/wgl.odin2
-rw-r--r--core/sys/windows/wglext.odin2
-rw-r--r--core/sys/windows/window_messages.odin2
-rw-r--r--core/sys/windows/winerror.odin3
-rw-r--r--core/sys/windows/winmm.odin2
-rw-r--r--core/sys/windows/winnls.odin2
-rw-r--r--core/sys/windows/winver.odin2
-rw-r--r--core/sys/windows/wow64_apiset.odin2
-rw-r--r--core/sys/windows/ws2_32.odin2
-rw-r--r--core/testing/events.odin2
-rw-r--r--core/testing/logging.odin2
-rw-r--r--core/testing/reporting.odin2
-rw-r--r--core/testing/runner.odin6
-rw-r--r--core/testing/runner_windows.odin22
-rw-r--r--core/testing/signal_handler.odin2
-rw-r--r--core/testing/signal_handler_libc.odin15
-rw-r--r--core/testing/signal_handler_other.odin10
-rw-r--r--core/testing/testing.odin12
-rw-r--r--core/text/edit/text_edit.odin9
-rw-r--r--core/text/table/doc.odin29
-rw-r--r--core/text/table/table.odin2
-rw-r--r--core/thread/thread.odin12
-rw-r--r--core/thread/thread_other.odin2
-rw-r--r--core/thread/thread_pool.odin14
-rw-r--r--core/thread/thread_unix.odin45
-rw-r--r--core/thread/thread_windows.odin16
-rw-r--r--core/time/datetime/internal.odin2
-rw-r--r--core/time/rfc3339.odin108
-rw-r--r--core/time/time.odin18
-rw-r--r--core/time/time_essence.odin2
-rw-r--r--core/time/time_js.odin4
-rw-r--r--core/time/time_orca.odin4
-rw-r--r--core/time/time_other.odin22
-rw-r--r--core/time/time_unix.odin4
-rw-r--r--core/time/time_wasi.odin4
-rw-r--r--core/time/time_windows.odin2
-rw-r--r--core/time/tsc_darwin.odin2
-rw-r--r--core/time/tsc_freebsd.odin4
-rw-r--r--core/time/tsc_linux.odin4
-rw-r--r--core/unicode/tools/generate_entity_table.odin2
-rw-r--r--examples/all/all_experimental.odin2
-rw-r--r--examples/all/all_linux.odin2
-rw-r--r--examples/all/all_posix.odin2
-rw-r--r--examples/demo/demo.odin2
-rw-r--r--src/bug_report.cpp10
-rw-r--r--src/build_settings.cpp19
-rw-r--r--src/check_builtin.cpp113
-rw-r--r--src/check_decl.cpp24
-rw-r--r--src/check_expr.cpp185
-rw-r--r--src/check_stmt.cpp27
-rw-r--r--src/check_type.cpp32
-rw-r--r--src/checker.cpp139
-rw-r--r--src/checker_builtin_procs.hpp7
-rw-r--r--src/entity.cpp1
-rw-r--r--src/gb/gb.h29
-rw-r--r--src/linker.cpp18
-rw-r--r--src/llvm_abi.cpp9
-rw-r--r--src/llvm_backend.cpp7
-rw-r--r--src/llvm_backend.hpp2
-rw-r--r--src/llvm_backend_const.cpp4
-rw-r--r--src/llvm_backend_debug.cpp147
-rw-r--r--src/llvm_backend_expr.cpp77
-rw-r--r--src/llvm_backend_proc.cpp62
-rw-r--r--src/llvm_backend_stmt.cpp7
-rw-r--r--src/llvm_backend_type.cpp2
-rw-r--r--src/llvm_backend_utility.cpp2
-rw-r--r--src/main.cpp80
-rw-r--r--src/microsoft_craziness.h10
-rw-r--r--src/parser.cpp272
-rw-r--r--src/parser.hpp6
-rw-r--r--src/threading.cpp3
-rw-r--r--src/tokenizer.cpp15
-rw-r--r--src/types.cpp36
-rw-r--r--tests/core/bytes/test_core_bytes.odin8
-rw-r--r--tests/core/c/libc/test_core_libc_complex_pow.odin24
-rw-r--r--tests/core/container/test_core_bit_array.odin244
-rw-r--r--tests/core/container/test_core_rbtree.odin2
-rw-r--r--tests/core/container/test_core_small_array.odin19
-rw-r--r--tests/core/encoding/json/test_core_json.odin2
-rw-r--r--tests/core/encoding/xml/test_core_xml.odin10
-rw-r--r--tests/core/flags/test_core_flags.odin33
-rw-r--r--tests/core/io/test_core_io.odin735
-rw-r--r--tests/core/mem/test_mem_dynamic_pool.odin4
-rw-r--r--tests/core/net/test_core_net.odin52
-rw-r--r--tests/core/net/test_core_net_freebsd.odin2
-rw-r--r--tests/core/normal.odin3
-rw-r--r--tests/core/odin/test_file_tags.odin155
-rw-r--r--tests/core/runtime/test_core_runtime.odin3
-rw-r--r--tests/core/slice/test_core_slice.odin32
-rw-r--r--tests/core/strings/test_core_strings.odin46
-rw-r--r--tests/core/sync/chan/test_core_sync_chan.odin274
-rw-r--r--tests/core/sync/test_core_sync.odin714
-rw-r--r--tests/core/sys/posix/posix.odin2
-rw-r--r--tests/core/sys/posix/structs.odin5
-rw-r--r--tests/core/sys/windows/test_clipboard.odin55
-rw-r--r--tests/core/sys/windows/test_kernel32.odin2
-rw-r--r--tests/core/sys/windows/test_ole32.odin2
-rw-r--r--tests/core/sys/windows/test_user32.odin2
-rw-r--r--tests/core/sys/windows/test_windows.odin2
-rw-r--r--tests/core/sys/windows/test_windows_generated.odin2
-rw-r--r--tests/core/sys/windows/test_winerror.odin2
-rw-r--r--tests/core/sys/windows/win32gen/win32gen.cpp2
-rw-r--r--tests/core/time/test_core_time.odin57
-rw-r--r--tests/core/unicode/test_core_unicode.odin3
-rw-r--r--tests/documentation/documentation_tester.odin2
-rw-r--r--tests/issues/run.bat1
-rwxr-xr-xtests/issues/run.sh1
-rw-r--r--tests/issues/test_issue_4210.odin85
-rw-r--r--tests/vendor/all.odin4
-rw-r--r--tests/vendor/glfw/test_vendor_glfw.odin2
-rw-r--r--tests/vendor/lua/5.4/test_vendor_lua.5.4.odin2
-rw-r--r--vendor/ENet/unix.odin2
-rw-r--r--vendor/ENet/win32.odin2
-rw-r--r--vendor/box2d/box2d.odin22
-rw-r--r--vendor/box2d/box2d_wasm.odin4
-rwxr-xr-xvendor/box2d/build_box2d.sh16
-rw-r--r--vendor/box2d/lib/box2d_darwin_amd64_avx2.abin913288 -> 355808 bytes
-rw-r--r--vendor/box2d/lib/box2d_darwin_amd64_sse2.abin913288 -> 355808 bytes
-rw-r--r--vendor/box2d/lib/box2d_darwin_arm64.abin875336 -> 290152 bytes
-rwxr-xr-xvendor/box2d/lib/box2d_wasm.obin0 -> 433031 bytes
-rwxr-xr-xvendor/box2d/lib/box2d_wasm_simd.obin0 -> 405135 bytes
-rw-r--r--vendor/box2d/wasm.Makefile32
-rw-r--r--vendor/cgltf/cgltf.odin5
-rw-r--r--vendor/cgltf/cgltf_wasm.odin4
-rw-r--r--vendor/cgltf/lib/cgltf_wasm.obin0 -> 112327 bytes
-rw-r--r--vendor/cgltf/src/Makefile4
-rw-r--r--vendor/commonmark/cmark.odin2
-rw-r--r--vendor/commonmark/doc.odin2
-rw-r--r--vendor/directx/d3d12/d3d12.odin8
-rw-r--r--vendor/directx/dxc/dxcapi.odin4
-rw-r--r--vendor/directx/dxc/dxcdef_unix.odin2
-rw-r--r--vendor/directx/dxc/dxcdef_windows.odin2
-rw-r--r--vendor/egl/egl.odin2
-rw-r--r--vendor/fontstash/fontstash.odin2
-rw-r--r--vendor/fontstash/fontstash_os.odin2
-rw-r--r--vendor/fontstash/fontstash_other.odin2
-rw-r--r--vendor/glfw/native_darwin.odin2
-rw-r--r--vendor/glfw/native_linux.odin2
-rw-r--r--vendor/glfw/native_windows.odin2
-rw-r--r--vendor/libc/README.md12
-rw-r--r--vendor/libc/assert.odin15
-rw-r--r--vendor/libc/include/assert.h16
-rw-r--r--vendor/libc/include/math.h21
-rw-r--r--vendor/libc/include/stdio.h47
-rw-r--r--vendor/libc/include/stdlib.h19
-rw-r--r--vendor/libc/include/string.h21
-rw-r--r--vendor/libc/libc.odin25
-rw-r--r--vendor/libc/math.odin100
-rw-r--r--vendor/libc/stdio.odin106
-rw-r--r--vendor/libc/stdlib.odin119
-rw-r--r--vendor/libc/string.odin111
-rw-r--r--vendor/lua/5.4/lua.odin2
-rw-r--r--vendor/miniaudio/common_unix.odin2
-rw-r--r--vendor/miniaudio/decoding.odin6
-rw-r--r--vendor/miniaudio/device_io_types.odin6
-rw-r--r--vendor/nanovg/gl/gl.odin2
-rw-r--r--vendor/nanovg/nanovg.odin2
-rw-r--r--vendor/raylib/raylib.odin31
-rw-r--r--vendor/sdl2/sdl2.odin6
-rw-r--r--vendor/sdl2/sdl_events.odin8
-rw-r--r--vendor/sdl2/sdl_gamecontroller.odin46
-rw-r--r--vendor/sdl2/sdl_touch.odin8
-rw-r--r--vendor/stb/image/stb_image.odin56
-rw-r--r--vendor/stb/image/stb_image_resize.odin9
-rw-r--r--vendor/stb/image/stb_image_wasm.odin4
-rw-r--r--vendor/stb/image/stb_image_write.odin24
-rw-r--r--vendor/stb/lib/darwin/stb_truetype.abin159344 -> 138088 bytes
-rw-r--r--vendor/stb/lib/stb_image_resize_wasm.obin0 -> 27646 bytes
-rw-r--r--vendor/stb/lib/stb_image_wasm.obin0 -> 78144 bytes
-rw-r--r--vendor/stb/lib/stb_image_write_wasm.obin0 -> 24259 bytes
-rw-r--r--vendor/stb/lib/stb_rect_pack_wasm.obin0 -> 3683 bytes
-rw-r--r--vendor/stb/lib/stb_sprintf_wasm.obin0 -> 13793 bytes
-rw-r--r--vendor/stb/lib/stb_truetype.libbin175530 -> 170652 bytes
-rw-r--r--vendor/stb/lib/stb_truetype_wasm.obin41425 -> 46482 bytes
-rw-r--r--vendor/stb/rect_pack/stb_rect_pack.odin5
-rw-r--r--vendor/stb/rect_pack/stb_rect_pack_wasm.odin4
-rw-r--r--vendor/stb/sprintf/stb_sprintf.odin37
-rw-r--r--vendor/stb/src/Makefile14
-rw-r--r--vendor/stb/src/stb_sprintf.c2
-rw-r--r--vendor/stb/src/stb_sprintf.h1906
-rw-r--r--vendor/stb/src/stb_truetype.c3
-rw-r--r--vendor/stb/src/stb_truetype_wasm.c46
-rw-r--r--vendor/stb/truetype/stb_truetype.odin7
-rw-r--r--vendor/stb/truetype/stb_truetype_wasm.odin82
-rw-r--r--vendor/wasm/README.md6
-rw-r--r--vendor/wgpu/README.md4
-rw-r--r--vendor/wgpu/examples/glfw/main.odin4
-rw-r--r--vendor/wgpu/examples/glfw/os_glfw.odin2
-rw-r--r--vendor/wgpu/examples/sdl2/main.odin4
-rw-r--r--vendor/wgpu/examples/sdl2/os_sdl2.odin2
-rw-r--r--vendor/wgpu/glfwglue/glue.odin6
-rw-r--r--vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dllbin8013824 -> 9427968 bytes
-rw-r--r--vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll.libbin69402 -> 58114 bytes
-rw-r--r--vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.libbin41795760 -> 53420432 bytes
-rw-r--r--vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdbbin3731456 -> 4108288 bytes
-rw-r--r--vendor/wgpu/sdl2glue/glue.odin6
-rw-r--r--vendor/wgpu/sdl2glue/glue_linux.odin2
-rw-r--r--vendor/wgpu/wgpu.js187
-rw-r--r--vendor/wgpu/wgpu.odin166
-rw-r--r--vendor/x11/xlib/xlib_const.odin2
-rw-r--r--vendor/x11/xlib/xlib_keysym.odin3352
-rw-r--r--vendor/x11/xlib/xlib_procs.odin2
-rw-r--r--vendor/x11/xlib/xlib_types.odin624
597 files changed, 17121 insertions, 6385 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 455a451e7..421b5c586 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -32,9 +32,9 @@ jobs:
gmake -C vendor/miniaudio/src
./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 -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- ./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
(cd tests/issues; ./run.sh)
build_freebsd:
name: FreeBSD Build, Check, and Test
@@ -60,9 +60,9 @@ jobs:
gmake -C vendor/cgltf/src
gmake -C vendor/miniaudio/src
./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 -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- ./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
(cd tests/issues; ./run.sh)
ci:
strategy:
@@ -116,13 +116,13 @@ jobs:
- name: Odin check examples/all
run: ./odin check examples/all -strict-style
- name: Normal Core library tests
- run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Optimized Core library tests
- run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Vendor library tests
- run: ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Internals tests
- run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: GitHub Issue tests
run: |
cd tests/issues
@@ -176,33 +176,33 @@ jobs:
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
- odin run examples/demo -debug
+ odin run examples/demo -debug -vet -strict-style -disallow-do
- name: Odin check examples/all
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
- odin check examples/all -strict-style
+ odin check examples/all -vet -strict-style -disallow-do
- name: Core library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
- odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Optimized core library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
- odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Vendor library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
copy vendor\lua\5.4\windows\*.dll .
- odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Odin internals tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
- odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+ odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Odin documentation tests
shell: cmd
run: |
@@ -257,16 +257,16 @@ jobs:
run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross
- name: Odin run
- run: ./odin run examples/demo -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+ run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath
- name: Odin run -debug
- run: ./odin run examples/demo -debug -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+ run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath
- name: Normal Core library tests
- run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+ run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath
- name: Optimized Core library tests
- run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+ run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath
- name: Internals tests
- run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+ run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 0c5526d0f..6243d1922 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -36,43 +36,54 @@ jobs:
cp -r bin dist
cp -r examples dist
- name: Upload artifact
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v4
with:
name: windows_artifacts
path: dist
- build_ubuntu:
- name: Ubuntu Build
+ build_linux:
+ name: Linux Build
if: github.repository == 'odin-lang/Odin'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+ - uses: jirutka/setup-alpine@v1
+ with:
+ branch: v3.20
- name: (Linux) Download LLVM
run: |
- wget https://apt.llvm.org/llvm.sh
- chmod +x llvm.sh
- sudo ./llvm.sh 18
- echo "/usr/lib/llvm-18/bin" >> $GITHUB_PATH
+ apk add --no-cache \
+ musl-dev llvm18-dev clang18 git mold lz4 \
+ libxml2-static llvm18-static zlib-static zstd-static \
+ make
+ shell: alpine.sh --root {0}
- name: build odin
- run: make nightly
+ # NOTE: this build does slow compile times because of musl
+ run: ci/build_linux_static.sh
+ shell: alpine.sh {0}
- name: Odin run
run: ./odin run examples/demo
- name: Copy artifacts
run: |
- mkdir dist
- cp odin dist
- cp LICENSE dist
- cp -r shared dist
- cp -r base dist
- cp -r core dist
- cp -r vendor dist
- cp -r examples dist
- # Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
- zip -r dist.zip dist
+ FILE="odin-linux-amd64-nightly+$(date -I)"
+ mkdir $FILE
+ cp odin $FILE
+ cp LICENSE $FILE
+ cp -r shared $FILE
+ cp -r base $FILE
+ cp -r core $FILE
+ cp -r vendor $FILE
+ cp -r examples $FILE
+ # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
+ tar -czvf dist.tar.gz $FILE
+ - name: Odin run
+ run: |
+ FILE="odin-linux-amd64-nightly+$(date -I)"
+ $FILE/odin run examples/demo
- name: Upload artifact
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v4
with:
- name: ubuntu_artifacts
- path: dist.zip
+ name: linux_artifacts
+ path: dist.tar.gz
build_macos:
name: MacOS Build
if: github.repository == 'odin-lang/Odin'
@@ -89,24 +100,27 @@ jobs:
run: CXXFLAGS="-L/usr/lib/system -L/usr/lib" make nightly
- name: Bundle
run: |
- mkdir dist
- cp odin dist
- cp LICENSE dist
- cp -r shared dist
- cp -r base dist
- cp -r core dist
- cp -r vendor dist
- cp -r examples dist
- dylibbundler -b -x dist/odin -d dist/libs -od -p @executable_path/libs
- # Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
- zip -r dist.zip dist
+ FILE="odin-macos-amd64-nightly+$(date -I)"
+ mkdir $FILE
+ cp odin $FILE
+ cp LICENSE $FILE
+ cp -r shared $FILE
+ cp -r base $FILE
+ cp -r core $FILE
+ cp -r vendor $FILE
+ cp -r examples $FILE
+ dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
+ # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
+ tar -czvf dist.tar.gz $FILE
- name: Odin run
- run: ./dist/odin run examples/demo
+ run: |
+ FILE="odin-macos-amd64-nightly+$(date -I)"
+ $FILE/odin run examples/demo
- name: Upload artifact
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v4
with:
name: macos_artifacts
- path: dist.zip
+ path: dist.tar.gz
build_macos_arm:
name: MacOS ARM Build
if: github.repository == 'odin-lang/Odin'
@@ -123,30 +137,33 @@ jobs:
run: CXXFLAGS="-L/usr/lib/system -L/usr/lib" make nightly
- name: Bundle
run: |
- mkdir dist
- cp odin dist
- cp LICENSE dist
- cp -r shared dist
- cp -r base dist
- cp -r core dist
- cp -r vendor dist
- cp -r examples dist
- dylibbundler -b -x dist/odin -d dist/libs -od -p @executable_path/libs
- # Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
- zip -r dist.zip dist
+ FILE="odin-macos-arm64-nightly+$(date -I)"
+ mkdir $FILE
+ cp odin $FILE
+ cp LICENSE $FILE
+ cp -r shared $FILE
+ cp -r base $FILE
+ cp -r core $FILE
+ cp -r vendor $FILE
+ cp -r examples $FILE
+ dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
+ # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
+ tar -czvf dist.tar.gz $FILE
- name: Odin run
- run: ./dist/odin run examples/demo
+ run: |
+ FILE="odin-macos-arm64-nightly+$(date -I)"
+ $FILE/odin run examples/demo
- name: Upload artifact
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v4
with:
name: macos_arm_artifacts
- path: dist.zip
+ path: dist.tar.gz
upload_b2:
runs-on: [ubuntu-latest]
- needs: [build_windows, build_macos, build_macos_arm, build_ubuntu]
+ needs: [build_windows, build_macos, build_macos_arm, build_linux]
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-python@v2
+ - uses: actions/setup-python@v5
with:
python-version: '3.8.x'
@@ -160,24 +177,33 @@ jobs:
run: python -c "import sys; print(sys.version)"
- name: Download Windows artifacts
- uses: actions/download-artifact@v1
+
+ uses: actions/download-artifact@v4.1.7
with:
name: windows_artifacts
+ path: windows_artifacts
- name: Download Ubuntu artifacts
- uses: actions/download-artifact@v1
+ uses: actions/download-artifact@v4.1.7
with:
- name: ubuntu_artifacts
+ name: linux_artifacts
+ path: linux_artifacts
- name: Download macOS artifacts
- uses: actions/download-artifact@v1
+ uses: actions/download-artifact@v4.1.7
with:
name: macos_artifacts
+ path: macos_artifacts
- name: Download macOS arm artifacts
- uses: actions/download-artifact@v1
+ uses: actions/download-artifact@v4.1.7
with:
name: macos_arm_artifacts
+ path: macos_arm_artifacts
+
+ - name: Debug
+ run: |
+ tree -L 2
- name: Create archives and upload
shell: bash
@@ -187,9 +213,10 @@ jobs:
BUCKET: ${{ secrets.B2_BUCKET }}
DAYS_TO_KEEP: ${{ secrets.B2_DAYS_TO_KEEP }}
run: |
+ file linux_artifacts/dist.tar.gz
python3 ci/nightly.py artifact windows-amd64 windows_artifacts/
- python3 ci/nightly.py artifact ubuntu-amd64 ubuntu_artifacts/dist.zip
- python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.zip
- python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.zip
+ python3 ci/nightly.py artifact linux-amd64 linux_artifacts/dist.tar.gz
+ python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.tar.gz
+ python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.tar.gz
python3 ci/nightly.py prune
python3 ci/nightly.py json
diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin
index b7e8c1189..744a899c0 100644
--- a/base/intrinsics/intrinsics.odin
+++ b/base/intrinsics/intrinsics.odin
@@ -1,5 +1,5 @@
// This is purely for documentation
-//+build ignore
+#+build ignore
package intrinsics
// Package-Related
@@ -219,6 +219,8 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info ---
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
+type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) ---
+
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
constant_log2 :: proc($v: $T) -> T where type_is_integer(T) ---
diff --git a/base/runtime/core.odin b/base/runtime/core.odin
index cc80e68a5..a5a3a4d8c 100644
--- a/base/runtime/core.odin
+++ b/base/runtime/core.odin
@@ -18,7 +18,7 @@
// This could change at a later date if the all these data structures are
// implemented within the compiler rather than in this "preload" file
//
-//+no-instrumentation
+#+no-instrumentation
package runtime
import "base:intrinsics"
@@ -546,10 +546,23 @@ Odin_OS_Type :: type_of(ODIN_OS)
arm64,
wasm32,
wasm64p32,
+ riscv64,
}
*/
Odin_Arch_Type :: type_of(ODIN_ARCH)
+Odin_Arch_Types :: bit_set[Odin_Arch_Type]
+
+ALL_ODIN_ARCH_TYPES :: Odin_Arch_Types{
+ .amd64,
+ .i386,
+ .arm32,
+ .arm64,
+ .wasm32,
+ .wasm64p32,
+ .riscv64,
+}
+
/*
// Defined internally by the compiler
Odin_Build_Mode_Type :: enum int {
@@ -573,6 +586,22 @@ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
*/
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
+Odin_OS_Types :: bit_set[Odin_OS_Type]
+
+ALL_ODIN_OS_TYPES :: Odin_OS_Types{
+ .Windows,
+ .Darwin,
+ .Linux,
+ .Essence,
+ .FreeBSD,
+ .OpenBSD,
+ .NetBSD,
+ .Haiku,
+ .WASI,
+ .JS,
+ .Orca,
+ .Freestanding,
+}
/*
// Defined internally by the compiler
diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin
index 9af155174..67d249d11 100644
--- a/base/runtime/core_builtin.odin
+++ b/base/runtime/core_builtin.odin
@@ -68,7 +68,7 @@ copy :: proc{copy_slice, copy_from_string}
// 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 {
+unordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
n := len(array)-1
if index != n {
@@ -82,7 +82,7 @@ unordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_loca
// 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 {
+ordered_remove :: proc(array: ^$D/[dynamic]$T, #any_int index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
if index+1 < len(array) {
copy(array[index:], array[index+1:])
@@ -95,7 +95,7 @@ ordered_remove :: proc(array: ^$D/[dynamic]$T, index: int, loc := #caller_locati
// Note: This is an O(N) operation.
// Note: If the range is out of bounds, this procedure will panic.
@builtin
-remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_location) #no_bounds_check {
+remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #caller_location) #no_bounds_check {
slice_expr_error_lo_hi_loc(loc, lo, hi, len(array))
n := max(hi-lo, 0)
if n > 0 {
@@ -602,7 +602,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i
@builtin
-inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil {
return
}
@@ -620,7 +620,7 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast arg: E,
}
@builtin
-inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil {
return
}
@@ -643,7 +643,7 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args:
}
@builtin
-inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil {
return
}
@@ -668,7 +668,7 @@ inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
@builtin
-assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+assign_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if index < len(array) {
array[index] = arg
ok = true
@@ -682,7 +682,7 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
@builtin
-assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+assign_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
new_size := index + len(args)
if len(args) == 0 {
ok = true
@@ -699,7 +699,7 @@ assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args:
@builtin
-assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
new_size := index + len(arg)
if len(arg) == 0 {
ok = true
@@ -838,7 +838,7 @@ non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: i
Note: Prefer the procedure group `shrink`
*/
-shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
+shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
return _shrink_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), new_cap, loc)
}
@@ -913,7 +913,7 @@ card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
-assert :: proc(condition: bool, message := "", loc := #caller_location) {
+assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
if !condition {
// NOTE(bill): This is wrapped in a procedure call
// to improve performance to make the CPU not
@@ -952,7 +952,7 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! {
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
-assert_contextless :: proc "contextless" (condition: bool, message := "", loc := #caller_location) {
+assert_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
if !condition {
// NOTE(bill): This is wrapped in a procedure call
// to improve performance to make the CPU not
diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin
index 7f7f5f086..2980b7a9e 100644
--- a/base/runtime/core_builtin_soa.odin
+++ b/base/runtime/core_builtin_soa.odin
@@ -76,7 +76,7 @@ raw_soa_footer :: proc{
@(builtin, require_results)
-make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
+make_soa_aligned :: proc($T: typeid/#soa[]$E, #any_int length, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
if length <= 0 {
return
}
@@ -135,7 +135,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
}
@(builtin, require_results)
-make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
+make_soa_slice :: proc($T: typeid/#soa[]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
return make_soa_aligned(T, length, align_of(E), allocator, loc)
}
@@ -172,7 +172,7 @@ make_soa :: proc{
@builtin
-resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
+resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
if array == nil {
return nil
}
@@ -183,7 +183,7 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_locat
}
@builtin
-non_zero_resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
+non_zero_resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
if array == nil {
return nil
}
@@ -194,12 +194,12 @@ non_zero_resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #cal
}
@builtin
-reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
+reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int 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 {
+non_zero_reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_soa(array, capacity, false, loc)
}
@@ -484,7 +484,7 @@ into_dynamic_soa :: proc(array: $T/#soa[]$E) -> #soa[dynamic]E {
// Note: If you the elements to remain in their order, use `ordered_remove_soa`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin
-unordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #caller_location) #no_bounds_check {
+unordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
if index+1 < len(array) {
ti := type_info_of(typeid_of(T))
@@ -512,7 +512,7 @@ unordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #cal
// Note: If you the elements do not have to remain in their order, prefer `unordered_remove_soa`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin
-ordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #caller_location) #no_bounds_check {
+ordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
if index+1 < len(array) {
ti := type_info_of(typeid_of(T))
diff --git a/base/runtime/default_allocators_nil.odin b/base/runtime/default_allocators_nil.odin
index ce8519c10..e7a1b1a74 100644
--- a/base/runtime/default_allocators_nil.odin
+++ b/base/runtime/default_allocators_nil.odin
@@ -1,8 +1,8 @@
package runtime
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
+ size, alignment: int,
+ old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
return nil, .Out_Of_Memory
diff --git a/base/runtime/entry_unix.odin b/base/runtime/entry_unix.odin
index 5dfd37f99..e2223d5d6 100644
--- a/base/runtime/entry_unix.odin
+++ b/base/runtime/entry_unix.odin
@@ -1,6 +1,6 @@
-//+private
-//+build linux, darwin, freebsd, openbsd, netbsd, haiku
-//+no-instrumentation
+#+private
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+no-instrumentation
package runtime
import "base:intrinsics"
diff --git a/base/runtime/entry_wasm.odin b/base/runtime/entry_wasm.odin
index 99cd8201d..52bb0e072 100644
--- a/base/runtime/entry_wasm.odin
+++ b/base/runtime/entry_wasm.odin
@@ -1,6 +1,6 @@
-//+private
-//+build wasm32, wasm64p32
-//+no-instrumentation
+#+private
+#+build wasm32, wasm64p32
+#+no-instrumentation
package runtime
import "base:intrinsics"
diff --git a/base/runtime/entry_windows.odin b/base/runtime/entry_windows.odin
index 1e2dcc21a..8eb4cc7d1 100644
--- a/base/runtime/entry_windows.odin
+++ b/base/runtime/entry_windows.odin
@@ -1,6 +1,6 @@
-//+private
-//+build windows
-//+no-instrumentation
+#+private
+#+build windows
+#+no-instrumentation
package runtime
import "base:intrinsics"
diff --git a/base/runtime/heap_allocator.odin b/base/runtime/heap_allocator.odin
index a0a984f10..4b04dffef 100644
--- a/base/runtime/heap_allocator.odin
+++ b/base/runtime/heap_allocator.odin
@@ -20,25 +20,27 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
//
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr, old_size: int, zero_memory := true) -> ([]byte, Allocator_Error) {
+ // Not(flysand): We need to reserve enough space for alignment, which
+ // includes the user data itself, the space to store the pointer to
+ // allocation start, as well as the padding required to align both
+ // the user data and the pointer.
a := max(alignment, align_of(rawptr))
- space := size + a - 1
-
+ space := a-1 + size_of(rawptr) + size
allocated_mem: rawptr
- force_copy := old_ptr != nil && a > align_of(rawptr)
+ force_copy := old_ptr != nil && alignment > align_of(rawptr)
- if !force_copy && old_ptr != nil {
+ if old_ptr != nil && !force_copy {
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
- allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
+ allocated_mem = heap_resize(original_old_ptr, space)
} else {
- allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
+ allocated_mem = heap_alloc(space, zero_memory)
}
aligned_mem := rawptr(([^]u8)(allocated_mem)[size_of(rawptr):])
ptr := uintptr(aligned_mem)
- aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
- diff := int(aligned_ptr - ptr)
- if (size + diff) > space || allocated_mem == nil {
+ aligned_ptr := (ptr + uintptr(a)-1) & ~(uintptr(a)-1)
+ if allocated_mem == nil {
aligned_free(old_ptr)
aligned_free(allocated_mem)
return nil, .Out_Of_Memory
@@ -48,7 +50,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
([^]rawptr)(aligned_mem)[-1] = allocated_mem
if force_copy {
- mem_copy_non_overlapping(aligned_mem, old_ptr, old_size)
+ mem_copy_non_overlapping(aligned_mem, old_ptr, min(old_size, size))
aligned_free(old_ptr)
}
diff --git a/base/runtime/heap_allocator_orca.odin b/base/runtime/heap_allocator_orca.odin
index 9e719bcd0..be032a207 100644
--- a/base/runtime/heap_allocator_orca.odin
+++ b/base/runtime/heap_allocator_orca.odin
@@ -1,5 +1,5 @@
-//+build orca
-//+private
+#+build orca
+#+private
package runtime
foreign {
diff --git a/base/runtime/heap_allocator_other.odin b/base/runtime/heap_allocator_other.odin
index 8a7ad1a47..507dbf318 100644
--- a/base/runtime/heap_allocator_other.odin
+++ b/base/runtime/heap_allocator_other.odin
@@ -1,5 +1,5 @@
-//+build js, wasi, freestanding, essence
-//+private
+#+build js, wasi, freestanding, essence
+#+private
package runtime
_heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr {
diff --git a/base/runtime/heap_allocator_unix.odin b/base/runtime/heap_allocator_unix.odin
index 60af9e761..d4590d2dd 100644
--- a/base/runtime/heap_allocator_unix.odin
+++ b/base/runtime/heap_allocator_unix.odin
@@ -1,5 +1,5 @@
-//+build linux, darwin, freebsd, openbsd, netbsd, haiku
-//+private
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+private
package runtime
when ODIN_OS == .Darwin {
diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin
index ff60cf547..59811a525 100644
--- a/base/runtime/internal.odin
+++ b/base/runtime/internal.odin
@@ -1,4 +1,4 @@
-//+vet !cast
+#+vet !cast
package runtime
import "base:intrinsics"
@@ -118,16 +118,15 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r
DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
- if size == 0 {
- return nil, nil
- }
- if allocator.procedure == nil {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
+ if size == 0 || allocator.procedure == nil{
return nil, nil
}
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
}
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
if size == 0 || allocator.procedure == nil {
return nil, nil
}
@@ -135,6 +134,7 @@ mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, a
}
mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
if size == 0 || allocator.procedure == nil {
return nil, nil
}
@@ -174,6 +174,7 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
}
_mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
if allocator.procedure == nil {
return nil, nil
}
@@ -215,9 +216,11 @@ _mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignmen
}
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
return _mem_resize(ptr, old_size, new_size, alignment, allocator, true, loc)
}
non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
+ assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
}
diff --git a/base/runtime/os_specific_bsd.odin b/base/runtime/os_specific_bsd.odin
index 46ce51166..5d198484b 100644
--- a/base/runtime/os_specific_bsd.odin
+++ b/base/runtime/os_specific_bsd.odin
@@ -1,5 +1,5 @@
-//+build freebsd, openbsd, netbsd
-//+private
+#+build freebsd, openbsd, netbsd
+#+private
package runtime
foreign import libc "system:c"
diff --git a/base/runtime/os_specific_darwin.odin b/base/runtime/os_specific_darwin.odin
index 1bf29e785..907899d7c 100644
--- a/base/runtime/os_specific_darwin.odin
+++ b/base/runtime/os_specific_darwin.odin
@@ -1,5 +1,5 @@
-//+build darwin
-//+private
+#+build darwin
+#+private
package runtime
import "base:intrinsics"
diff --git a/base/runtime/os_specific_freestanding.odin b/base/runtime/os_specific_freestanding.odin
index 08ca4aa55..f975f61b8 100644
--- a/base/runtime/os_specific_freestanding.odin
+++ b/base/runtime/os_specific_freestanding.odin
@@ -1,5 +1,5 @@
-//+build freestanding
-//+private
+#+build freestanding
+#+private
package runtime
// TODO(bill): reimplement `os.write`
diff --git a/base/runtime/os_specific_haiku.odin b/base/runtime/os_specific_haiku.odin
index f8dafac3d..0d1ec7a03 100644
--- a/base/runtime/os_specific_haiku.odin
+++ b/base/runtime/os_specific_haiku.odin
@@ -1,5 +1,5 @@
-//+build haiku
-//+private
+#+build haiku
+#+private
package runtime
foreign import libc "system:c"
diff --git a/base/runtime/os_specific_js.odin b/base/runtime/os_specific_js.odin
index d35753604..f1d12c808 100644
--- a/base/runtime/os_specific_js.odin
+++ b/base/runtime/os_specific_js.odin
@@ -1,5 +1,5 @@
-//+build js
-//+private
+#+build js
+#+private
package runtime
foreign import "odin_env"
diff --git a/base/runtime/os_specific_linux.odin b/base/runtime/os_specific_linux.odin
index 146e647fb..d7b7371a7 100644
--- a/base/runtime/os_specific_linux.odin
+++ b/base/runtime/os_specific_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package runtime
import "base:intrinsics"
diff --git a/base/runtime/os_specific_orca.odin b/base/runtime/os_specific_orca.odin
index b6f5930ab..876d7d44b 100644
--- a/base/runtime/os_specific_orca.odin
+++ b/base/runtime/os_specific_orca.odin
@@ -1,5 +1,5 @@
-//+build orca
-//+private
+#+build orca
+#+private
package runtime
import "base:intrinsics"
diff --git a/base/runtime/os_specific_wasi.odin b/base/runtime/os_specific_wasi.odin
index b85d7adea..aa562050c 100644
--- a/base/runtime/os_specific_wasi.odin
+++ b/base/runtime/os_specific_wasi.odin
@@ -1,5 +1,5 @@
-//+build wasi
-//+private
+#+build wasi
+#+private
package runtime
foreign import wasi "wasi_snapshot_preview1"
diff --git a/base/runtime/os_specific_windows.odin b/base/runtime/os_specific_windows.odin
index 6da569aee..b966193ca 100644
--- a/base/runtime/os_specific_windows.odin
+++ b/base/runtime/os_specific_windows.odin
@@ -1,5 +1,5 @@
-//+build windows
-//+private
+#+build windows
+#+private
package runtime
foreign import kernel32 "system:Kernel32.lib"
diff --git a/base/runtime/procs_darwin.odin b/base/runtime/procs_darwin.odin
index 497978a76..4f4903d47 100644
--- a/base/runtime/procs_darwin.odin
+++ b/base/runtime/procs_darwin.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package runtime
foreign import "system:Foundation.framework"
diff --git a/base/runtime/procs_js.odin b/base/runtime/procs_js.odin
index d3e12410c..58bed808d 100644
--- a/base/runtime/procs_js.odin
+++ b/base/runtime/procs_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package runtime
init_default_context_for_js: Context
diff --git a/base/runtime/procs_wasm.odin b/base/runtime/procs_wasm.odin
index 9f2e9befc..7e03656ca 100644
--- a/base/runtime/procs_wasm.odin
+++ b/base/runtime/procs_wasm.odin
@@ -1,4 +1,4 @@
-//+build wasm32, wasm64p32
+#+build wasm32, wasm64p32
package runtime
@(private="file")
@@ -14,33 +14,57 @@ ti_uint :: struct #raw_union {
}
@(link_name="__ashlti3", linkage="strong")
-__ashlti3 :: proc "contextless" (la, ha: u64, b_: u32) -> i128 {
- bits_in_dword :: size_of(u32)*8
- b := u32(b_)
+__ashlti3 :: proc "contextless" (a: i128, b: u32) -> i128 {
+ bits :: 64
- input, result: ti_int
- input.lo, input.hi = la, ha
- if b & bits_in_dword != 0 {
+ input: ti_int = ---
+ result: ti_int = ---
+ input.all = a
+ if b & bits != 0 {
result.lo = 0
- result.hi = input.lo << (b-bits_in_dword)
+ result.hi = input.lo << (b-bits)
} else {
if b == 0 {
- return input.all
+ return a
}
result.lo = input.lo<<b
- result.hi = (input.hi<<b) | (input.lo>>(bits_in_dword-b))
+ result.hi = (input.hi<<b) | (input.lo>>(bits-b))
}
return result.all
}
+__ashlti3_unsigned :: proc "contextless" (a: u128, b: u32) -> u128 {
+ return cast(u128)__ashlti3(cast(i128)a, b)
+}
+
+@(link_name="__mulddi3", linkage="strong")
+__mulddi3 :: proc "contextless" (a, b: u64) -> i128 {
+ r: ti_int
+ bits :: 32
+
+ mask :: ~u64(0) >> bits
+ r.lo = (a & mask) * (b & mask)
+ t := r.lo >> bits
+ r.lo &= mask
+ t += (a >> bits) * (b & mask)
+ r.lo += (t & mask) << bits
+ r.hi = t >> bits
+ t = r.lo >> bits
+ r.lo &= mask
+ t += (b >> bits) * (a & mask)
+ r.lo += (t & mask) << bits
+ r.hi += t >> bits
+ r.hi += (a >> bits) * (b >> bits)
+ return r.all
+}
@(link_name="__multi3", linkage="strong")
-__multi3 :: proc "contextless" (la, ha, lb, hb: u64) -> i128 {
+__multi3 :: proc "contextless" (a, b: i128) -> i128 {
x, y, r: ti_int
- x.lo, x.hi = la, ha
- y.lo, y.hi = lb, hb
- r.all = i128(x.lo * y.lo) // TODO this is incorrect
+ x.all = a
+ y.all = b
+ r.all = __mulddi3(x.lo, y.lo)
r.hi += x.hi*y.lo + x.lo*y.hi
return r.all
}
@@ -54,18 +78,16 @@ udivti3 :: proc "c" (la, ha, lb, hb: u64) -> u128 {
}
@(link_name="__lshrti3", linkage="strong")
-__lshrti3 :: proc "c" (la, ha: u64, b: u32) -> i128 {
- bits :: size_of(u32)*8
+__lshrti3 :: proc "c" (a: i128, b: u32) -> i128 {
+ bits :: 64
input, result: ti_int
- input.lo = la
- input.hi = ha
-
+ input.all = a
if b & bits != 0 {
result.hi = 0
result.lo = input.hi >> (b - bits)
} else if b == 0 {
- return input.all
+ return a
} else {
result.hi = input.hi >> b
result.lo = (input.hi << (bits - b)) | (input.lo >> b)
diff --git a/base/runtime/procs_windows_amd64.odin b/base/runtime/procs_windows_amd64.odin
index ea495f5fa..81d2cfb5d 100644
--- a/base/runtime/procs_windows_amd64.odin
+++ b/base/runtime/procs_windows_amd64.odin
@@ -1,5 +1,5 @@
-//+private
-//+no-instrumentation
+#+private
+#+no-instrumentation
package runtime
foreign import kernel32 "system:Kernel32.lib"
diff --git a/base/runtime/procs_windows_i386.odin b/base/runtime/procs_windows_i386.odin
index 10422cf07..99c314228 100644
--- a/base/runtime/procs_windows_i386.odin
+++ b/base/runtime/procs_windows_i386.odin
@@ -1,5 +1,5 @@
-//+private
-//+no-instrumentation
+#+private
+#+no-instrumentation
package runtime
@require foreign import "system:int64.lib"
diff --git a/base/runtime/thread_management.odin b/base/runtime/thread_management.odin
new file mode 100644
index 000000000..cabd4691c
--- /dev/null
+++ b/base/runtime/thread_management.odin
@@ -0,0 +1,34 @@
+package runtime
+
+Thread_Local_Cleaner :: #type proc "odin" ()
+
+@(private="file")
+thread_local_cleaners: [8]Thread_Local_Cleaner
+
+// Add a procedure that will be run at the end of a thread for the purpose of
+// deallocating state marked as `thread_local`.
+//
+// Intended to be called in an `init` procedure of a package with
+// dynamically-allocated memory that is stored in `thread_local` variables.
+add_thread_local_cleaner :: proc "contextless" (p: Thread_Local_Cleaner) {
+ for &v in thread_local_cleaners {
+ if v == nil {
+ v = p
+ return
+ }
+ }
+ panic_contextless("There are no more thread-local cleaner slots available.")
+}
+
+// Run all of the thread-local cleaner procedures.
+//
+// Intended to be called by the internals of a threading API at the end of a
+// thread's lifetime.
+run_thread_local_cleaners :: proc "odin" () {
+ for p in thread_local_cleaners {
+ if p == nil {
+ break
+ }
+ p()
+ }
+}
diff --git a/base/runtime/wasm_allocator.odin b/base/runtime/wasm_allocator.odin
index 6bafaa489..574f3dd06 100644
--- a/base/runtime/wasm_allocator.odin
+++ b/base/runtime/wasm_allocator.odin
@@ -1,4 +1,4 @@
-//+build wasm32, wasm64p32
+#+build wasm32, wasm64p32
package runtime
import "base:intrinsics"
diff --git a/ci/build_linux_static.sh b/ci/build_linux_static.sh
new file mode 100755
index 000000000..f821cbb59
--- /dev/null
+++ b/ci/build_linux_static.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env sh
+# Intended for use in Alpine containers, see the "nightly" Github action for a list of dependencies
+
+CXX="clang++-18"
+LLVM_CONFIG="llvm-config-18"
+
+DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
+
+CPPFLAGS="-DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
+CXXFLAGS="-std=c++14 $($LLVM_CONFIG --cxxflags --ldflags)"
+
+LDFLAGS="-static -lm -lzstd -lz -lffi -pthread -ldl -fuse-ld=mold"
+LDFLAGS="$LDFLAGS $($LLVM_CONFIG --link-static --ldflags --libs --system-libs --libfiles)"
+LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
+
+EXTRAFLAGS="-DNIGHTLY -O3"
+
+set -x
+$CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
diff --git a/ci/nightly.py b/ci/nightly.py
index 7bd32899d..923c4e36d 100644
--- a/ci/nightly.py
+++ b/ci/nightly.py
@@ -2,7 +2,7 @@ import os
import sys
from zipfile import ZipFile, ZIP_DEFLATED
from b2sdk.v2 import InMemoryAccountInfo, B2Api
-from datetime import datetime
+from datetime import datetime, timezone
import json
UPLOAD_FOLDER = "nightly/"
@@ -22,7 +22,7 @@ def auth() -> bool:
pass # Not yet authenticated
err = b2_api.authorize_account("production", application_key_id, application_key)
- return err == None
+ return err is None
def get_bucket():
if not auth(): sys.exit(1)
@@ -32,30 +32,35 @@ def remove_prefix(text: str, prefix: str) -> str:
return text[text.startswith(prefix) and len(prefix):]
def create_and_upload_artifact_zip(platform: str, artifact: str) -> int:
- now = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
- destination_zip_name = "odin-{}-nightly+{}.zip".format(platform, now.strftime("%Y-%m-%d"))
+ now = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
- source_zip_name = artifact
- if not artifact.endswith(".zip"):
- print(f"Creating archive {destination_zip_name} from {artifact} and uploading to {bucket_name}")
+ source_archive: str
+ destination_name = f'odin-{platform}-nightly+{now.strftime("%Y-%m-%d")}'
- source_zip_name = destination_zip_name
- with ZipFile(source_zip_name, mode='w', compression=ZIP_DEFLATED, compresslevel=9) as z:
+ if platform.startswith("linux") or platform.startswith("macos"):
+ destination_name += ".tar.gz"
+ source_archive = artifact
+ else:
+ destination_name += ".zip"
+ source_archive = destination_name
+
+ print(f"Creating archive {destination_name} from {artifact} and uploading to {bucket_name}")
+ with ZipFile(source_archive, mode='w', compression=ZIP_DEFLATED, compresslevel=9) as z:
for root, directory, filenames in os.walk(artifact):
for file in filenames:
file_path = os.path.join(root, file)
zip_path = os.path.join("dist", os.path.relpath(file_path, artifact))
z.write(file_path, zip_path)
- if not os.path.exists(source_zip_name):
- print(f"Error: Newly created ZIP archive {source_zip_name} not found.")
- return 1
+ if not os.path.exists(source_archive):
+ print(f"Error: archive {source_archive} not found.")
+ return 1
- print("Uploading {} to {}".format(source_zip_name, UPLOAD_FOLDER + destination_zip_name))
+ print("Uploading {} to {}".format(source_archive, UPLOAD_FOLDER + destination_name))
bucket = get_bucket()
res = bucket.upload_local_file(
- source_zip_name, # Local file to upload
- "nightly/" + destination_zip_name, # B2 destination path
+ source_archive, # Local file to upload
+ "nightly/" + destination_name, # B2 destination path
)
return 0
@@ -65,8 +70,8 @@ def prune_artifacts():
bucket = get_bucket()
for file, _ in bucket.ls(UPLOAD_FOLDER, latest_only=False):
# Timestamp is in milliseconds
- date = datetime.fromtimestamp(file.upload_timestamp / 1_000.0).replace(hour=0, minute=0, second=0, microsecond=0)
- now = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
+ date = datetime.fromtimestamp(file.upload_timestamp / 1_000.0, tz=timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
+ now = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
delta = now - date
if delta.days > int(days_to_keep):
@@ -100,7 +105,7 @@ def update_nightly_json():
'sizeInBytes': size,
})
- now = datetime.utcnow().isoformat()
+ now = datetime.now(timezone.utc).isoformat()
nightly = json.dumps({
'last_updated' : now,
@@ -137,4 +142,4 @@ if __name__ == "__main__":
elif command == "json":
res = update_nightly_json()
- sys.exit(res) \ No newline at end of file
+ sys.exit(res)
diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin
index a7e9b1c64..f4d883353 100644
--- a/core/bytes/buffer.odin
+++ b/core/bytes/buffer.odin
@@ -144,6 +144,9 @@ buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) {
}
buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int, loc := #caller_location) -> (n: int, err: io.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
b.last_read = .Invalid
if offset < 0 {
err = .Invalid_Offset
@@ -246,10 +249,13 @@ buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.
}
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
b.last_read = .Invalid
if uint(offset) >= len(b.buf) {
- err = .Invalid_Offset
+ err = .EOF
return
}
n = copy(p, b.buf[offset:])
@@ -310,6 +316,27 @@ buffer_unread_rune :: proc(b: ^Buffer) -> io.Error {
return nil
}
+buffer_seek :: proc(b: ^Buffer, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
+ abs: i64
+ switch whence {
+ case .Start:
+ abs = offset
+ case .Current:
+ abs = i64(b.off) + offset
+ case .End:
+ abs = i64(len(b.buf)) + offset
+ case:
+ return 0, .Invalid_Whence
+ }
+
+ abs_int := int(abs)
+ if abs_int < 0 {
+ return 0, .Invalid_Offset
+ }
+ b.last_read = .Invalid
+ b.off = abs_int
+ return abs, nil
+}
buffer_read_bytes :: proc(b: ^Buffer, delim: byte) -> (line: []byte, err: io.Error) {
i := index_byte(b.buf[b.off:], delim)
@@ -395,14 +422,17 @@ _buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offse
return io._i64_err(buffer_write(b, p))
case .Write_At:
return io._i64_err(buffer_write_at(b, p, int(offset)))
+ case .Seek:
+ n, err = buffer_seek(b, offset, whence)
+ return
case .Size:
- n = i64(buffer_capacity(b))
+ n = i64(buffer_length(b))
return
case .Destroy:
buffer_destroy(b)
return
case .Query:
- return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy})
+ return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Destroy, .Query})
}
return 0, .Empty
}
diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin
index 5a510951e..c0d25bcce 100644
--- a/core/bytes/bytes.odin
+++ b/core/bytes/bytes.odin
@@ -334,7 +334,7 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
-index_byte :: proc(s: []byte, c: byte) -> (index: int) #no_bounds_check {
+index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds_check {
i, l := 0, len(s)
// Guard against small strings. On modern systems, it is ALWAYS
@@ -469,18 +469,16 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
-last_index_byte :: proc(s: []byte, c: byte) -> int #no_bounds_check {
+last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_check {
i := len(s)
// Guard against small strings. On modern systems, it is ALWAYS
// worth vectorizing assuming there is a hardware vector unit, and
// the data size is large enough.
if i < SIMD_REG_SIZE_128 {
- if i > 0 { // Handle s == nil.
- for /**/; i >= 0; i -= 1 {
- if s[i] == c {
- return i
- }
+ #reverse for ch, j in s {
+ if ch == c {
+ return j
}
}
return -1
diff --git a/core/bytes/reader.odin b/core/bytes/reader.odin
index 4b18345ba..2e1c5ed42 100644
--- a/core/bytes/reader.odin
+++ b/core/bytes/reader.odin
@@ -9,10 +9,11 @@ Reader :: struct {
prev_rune: int, // previous reading index of rune or < 0
}
-reader_init :: proc(r: ^Reader, s: []byte) {
+reader_init :: proc(r: ^Reader, s: []byte) -> io.Stream {
r.s = s
r.i = 0
r.prev_rune = -1
+ return reader_to_stream(r)
}
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
@@ -33,6 +34,9 @@ reader_size :: proc(r: ^Reader) -> i64 {
}
reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
if r.i >= i64(len(r.s)) {
return 0, .EOF
}
@@ -42,6 +46,9 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
return
}
reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
if off < 0 {
return 0, .Invalid_Offset
}
@@ -97,7 +104,6 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error {
return nil
}
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
- r.prev_rune = -1
abs: i64
switch whence {
case .Start:
@@ -114,6 +120,7 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E
return 0, .Invalid_Offset
}
r.i = abs
+ r.prev_rune = -1
return abs, nil
}
reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin
index 843b2f1b6..de429a6ec 100644
--- a/core/c/libc/errno.odin
+++ b/core/c/libc/errno.odin
@@ -98,6 +98,14 @@ when ODIN_OS == .Haiku {
ERANGE :: B_POSIX_ERROR_BASE + 17
}
+when ODIN_OS == .JS {
+ _ :: libc
+ _get_errno :: proc "c" () -> ^int {
+ @(static) errno: int
+ return &errno
+ }
+}
+
// Odin has no way to make an identifier "errno" behave as a function call to
// read the value, or to produce an lvalue such that you can assign a different
// error value to errno. To work around this, just expose it as a function like
diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin
index 4be00ff0b..a94a53696 100644
--- a/core/c/libc/stdio.odin
+++ b/core/c/libc/stdio.odin
@@ -89,6 +89,30 @@ when ODIN_OS == .Linux {
}
}
+when ODIN_OS == .JS {
+ fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
+
+ _IOFBF :: 0
+ _IOLBF :: 1
+ _IONBF :: 2
+
+ BUFSIZ :: 1024
+
+ EOF :: int(-1)
+
+ FOPEN_MAX :: 1000
+
+ FILENAME_MAX :: 4096
+
+ L_tmpnam :: 20
+
+ SEEK_SET :: 0
+ SEEK_CUR :: 1
+ SEEK_END :: 2
+
+ TMP_MAX :: 308915776
+}
+
when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
fpos_t :: distinct i64
@@ -368,7 +392,7 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
return 0, .Empty
case .Query:
- return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
+ return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query })
}
return
}
diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin
index 08c6fa6f0..98280e44b 100644
--- a/core/c/libc/stdlib.odin
+++ b/core/c/libc/stdlib.odin
@@ -10,6 +10,9 @@ when ODIN_OS == .Windows {
foreign import libc "system:c"
}
+@(require)
+import "base:runtime"
+
when ODIN_OS == .Windows {
RAND_MAX :: 0x7fff
@@ -145,6 +148,10 @@ aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
}
return _aligned_malloc(size=size, alignment=alignment)
+ } else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ context = runtime.default_context()
+ data, _ := runtime.mem_alloc_bytes(auto_cast size, auto_cast alignment)
+ return raw_data(data)
} else {
foreign libc {
aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
@@ -160,6 +167,9 @@ aligned_free :: #force_inline proc "c" (ptr: rawptr) {
_aligned_free :: proc(ptr: rawptr) ---
}
_aligned_free(ptr)
+ } else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ context = runtime.default_context()
+ runtime.mem_free(ptr)
} else {
free(ptr)
}
diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin
index cde9c7e6b..4ec4f3a7a 100644
--- a/core/c/libc/string.odin
+++ b/core/c/libc/string.odin
@@ -12,6 +12,7 @@ when ODIN_OS == .Windows {
foreign import libc "system:c"
}
+@(default_calling_convention="c")
foreign libc {
// 7.24.2 Copying functions
memcpy :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---
diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin
index 21859c602..6828793ec 100644
--- a/core/c/libc/time.odin
+++ b/core/c/libc/time.odin
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
}
}
-when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku {
+when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku || ODIN_OS == .JS {
@(default_calling_convention="c")
foreign libc {
// 7.27.2 Time manipulation functions
@@ -79,7 +79,7 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS =
} else {
@(private) LDIFFTIME :: "difftime"
@(private) LMKTIME :: "mktime"
- @(private) LTIME :: "ltime"
+ @(private) LTIME :: "time"
@(private) LCTIME :: "ctime"
@(private) LGMTIME :: "gmtime"
@(private) LLOCALTIME :: "localtime"
diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin
index a41fe7fac..b96410b4c 100644
--- a/core/c/libc/wctype.odin
+++ b/core/c/libc/wctype.odin
@@ -14,7 +14,7 @@ when ODIN_OS == .Windows {
wctrans_t :: distinct wchar_t
wctype_t :: distinct ushort
-} else when ODIN_OS == .Linux {
+} else when ODIN_OS == .Linux || ODIN_OS == .JS {
wctrans_t :: distinct intptr_t
wctype_t :: distinct ulong
diff --git a/core/compress/gzip/doc.odin b/core/compress/gzip/doc.odin
new file mode 100644
index 000000000..fd7ef5a19
--- /dev/null
+++ b/core/compress/gzip/doc.odin
@@ -0,0 +1,90 @@
+/*
+ Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
+ Made available under Odin's BSD-3 license.
+
+ List of contributors:
+ Jeroen van Rijn: Initial implementation.
+ Ginger Bill: Cosmetic changes.
+
+ A small GZIP implementation as an example.
+*/
+
+/*
+Example:
+ import "core:bytes"
+ import "core:os"
+ import "core:compress"
+ import "core:fmt"
+
+ // Small GZIP file with fextra, fname and fcomment present.
+ @private
+ TEST: []u8 = {
+ 0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
+ 0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
+ 0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
+ 0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
+ 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
+ 0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
+ 0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
+ }
+
+ main :: proc() {
+ // Set up output buffer.
+ buf := bytes.Buffer{}
+
+ stdout :: proc(s: string) {
+ os.write_string(os.stdout, s)
+ }
+ stderr :: proc(s: string) {
+ os.write_string(os.stderr, s)
+ }
+
+ args := os.args
+
+ if len(args) < 2 {
+ stderr("No input file specified.\n")
+ err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
+ if err == nil {
+ stdout("Displaying test vector: ")
+ stdout(bytes.buffer_to_string(&buf))
+ stdout("\n")
+ } else {
+ fmt.printf("gzip.load returned %v\n", err)
+ }
+ bytes.buffer_destroy(&buf)
+ os.exit(0)
+ }
+
+ // The rest are all files.
+ args = args[1:]
+ err: Error
+
+ for file in args {
+ if file == "-" {
+ // Read from stdin
+ s := os.stream_from_handle(os.stdin)
+ ctx := &compress.Context_Stream_Input{
+ input = s,
+ }
+ err = load(ctx, &buf)
+ } else {
+ err = load(file, &buf)
+ }
+ if err != nil {
+ if err != E_General.File_Not_Found {
+ stderr("File not found: ")
+ stderr(file)
+ stderr("\n")
+ os.exit(1)
+ }
+ stderr("GZIP returned an error.\n")
+ bytes.buffer_destroy(&buf)
+ os.exit(2)
+ }
+ stdout(bytes.buffer_to_string(&buf))
+ }
+ bytes.buffer_destroy(&buf)
+ }
+*/
+package compress_gzip
diff --git a/core/compress/gzip/example.odin b/core/compress/gzip/example.odin
deleted file mode 100644
index 09540aafc..000000000
--- a/core/compress/gzip/example.odin
+++ /dev/null
@@ -1,89 +0,0 @@
-//+build ignore
-package compress_gzip
-
-/*
- Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
- Made available under Odin's BSD-3 license.
-
- List of contributors:
- Jeroen van Rijn: Initial implementation.
- Ginger Bill: Cosmetic changes.
-
- A small GZIP implementation as an example.
-*/
-
-import "core:bytes"
-import "core:os"
-import "core:compress"
-import "core:fmt"
-
-// Small GZIP file with fextra, fname and fcomment present.
-@private
-TEST: []u8 = {
- 0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
- 0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
- 0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
- 0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
- 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
- 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
- 0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
- 0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
-}
-
-main :: proc() {
- // Set up output buffer.
- buf := bytes.Buffer{}
-
- stdout :: proc(s: string) {
- os.write_string(os.stdout, s)
- }
- stderr :: proc(s: string) {
- os.write_string(os.stderr, s)
- }
-
- args := os.args
-
- if len(args) < 2 {
- stderr("No input file specified.\n")
- err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
- if err == nil {
- stdout("Displaying test vector: ")
- stdout(bytes.buffer_to_string(&buf))
- stdout("\n")
- } else {
- fmt.printf("gzip.load returned %v\n", err)
- }
- bytes.buffer_destroy(&buf)
- os.exit(0)
- }
-
- // The rest are all files.
- args = args[1:]
- err: Error
-
- for file in args {
- if file == "-" {
- // Read from stdin
- s := os.stream_from_handle(os.stdin)
- ctx := &compress.Context_Stream_Input{
- input = s,
- }
- err = load(ctx, &buf)
- } else {
- err = load(file, &buf)
- }
- if err != nil {
- if err != E_General.File_Not_Found {
- stderr("File not found: ")
- stderr(file)
- stderr("\n")
- os.exit(1)
- }
- stderr("GZIP returned an error.\n")
- bytes.buffer_destroy(&buf)
- os.exit(2)
- }
- stdout(bytes.buffer_to_string(&buf))
- }
- bytes.buffer_destroy(&buf)
-}
diff --git a/core/compress/shoco/model.odin b/core/compress/shoco/model.odin
index f62236c00..919563441 100644
--- a/core/compress/shoco/model.odin
+++ b/core/compress/shoco/model.odin
@@ -4,7 +4,6 @@
which is an English word model.
*/
-// package shoco is an implementation of the shoco short string compressor
package compress_shoco
DEFAULT_MODEL :: Shoco_Model {
@@ -145,4 +144,4 @@ DEFAULT_MODEL :: Shoco_Model {
{ 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 },
{ 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 },
},
-} \ No newline at end of file
+}
diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin
index 269dd8875..b393b8356 100644
--- a/core/compress/shoco/shoco.odin
+++ b/core/compress/shoco/shoco.odin
@@ -8,7 +8,7 @@
An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm.
*/
-// package shoco is an implementation of the shoco short string compressor
+// package shoco is an implementation of the shoco short string compressor.
package compress_shoco
import "base:intrinsics"
@@ -308,4 +308,4 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
resize(&buf, length) or_return
return buf[:length], result
}
-compress :: proc{compress_string_to_buffer, compress_string} \ No newline at end of file
+compress :: proc{compress_string_to_buffer, compress_string}
diff --git a/core/compress/zlib/doc.odin b/core/compress/zlib/doc.odin
new file mode 100644
index 000000000..0a5b4eb40
--- /dev/null
+++ b/core/compress/zlib/doc.odin
@@ -0,0 +1,50 @@
+/*
+ Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
+ Made available under Odin's BSD-3 license.
+
+ List of contributors:
+ Jeroen van Rijn: Initial implementation.
+
+ An example of how to use `zlib.inflate`.
+*/
+
+/*
+Example:
+ package main
+
+ import "core:bytes"
+ import "core:fmt"
+
+ main :: proc() {
+ ODIN_DEMO := []u8{
+ 120, 218, 101, 144, 65, 110, 131, 48, 16, 69, 215, 246, 41, 190, 44, 69, 73, 32, 148, 182,
+ 75, 75, 28, 32, 251, 46, 217, 88, 238, 0, 86, 192, 32, 219, 36, 170, 170, 172, 122, 137,
+ 238, 122, 197, 30, 161, 70, 162, 20, 81, 203, 139, 25, 191, 255, 191, 60, 51, 40, 125, 81,
+ 53, 33, 144, 15, 156, 155, 110, 232, 93, 128, 208, 189, 35, 89, 117, 65, 112, 222, 41, 99,
+ 33, 37, 6, 215, 235, 195, 17, 239, 156, 197, 170, 118, 170, 131, 44, 32, 82, 164, 72, 240,
+ 253, 245, 249, 129, 12, 185, 224, 76, 105, 61, 118, 99, 171, 66, 239, 38, 193, 35, 103, 85,
+ 172, 66, 127, 33, 139, 24, 244, 235, 141, 49, 204, 223, 76, 208, 205, 204, 166, 7, 173, 60,
+ 97, 159, 238, 37, 214, 41, 105, 129, 167, 5, 102, 27, 152, 173, 97, 178, 129, 73, 129, 231,
+ 5, 230, 27, 152, 175, 225, 52, 192, 127, 243, 170, 157, 149, 18, 121, 142, 115, 109, 227, 122,
+ 64, 87, 114, 111, 161, 49, 182, 6, 181, 158, 162, 226, 206, 167, 27, 215, 246, 48, 56, 99,
+ 67, 117, 16, 47, 13, 45, 35, 151, 98, 231, 75, 1, 173, 90, 61, 101, 146, 71, 136, 244,
+ 170, 218, 145, 176, 123, 45, 173, 56, 113, 134, 191, 51, 219, 78, 235, 95, 28, 249, 253, 7,
+ 159, 150, 133, 125,
+ }
+ OUTPUT_SIZE :: 432
+
+ buf: bytes.Buffer
+
+ // We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
+ err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
+ defer bytes.buffer_destroy(&buf)
+
+ if err != nil {
+ fmt.printf("\nError: %v\n", err)
+ }
+ s := bytes.buffer_to_string(&buf)
+ fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
+ assert(len(s) == OUTPUT_SIZE)
+ }
+*/
+package compress_zlib
diff --git a/core/compress/zlib/example.odin b/core/compress/zlib/example.odin
deleted file mode 100644
index fedd6671d..000000000
--- a/core/compress/zlib/example.odin
+++ /dev/null
@@ -1,47 +0,0 @@
-//+build ignore
-package compress_zlib
-
-/*
- Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
- Made available under Odin's BSD-3 license.
-
- List of contributors:
- Jeroen van Rijn: Initial implementation.
-
- An example of how to use `zlib.inflate`.
-*/
-
-import "core:bytes"
-import "core:fmt"
-
-main :: proc() {
- ODIN_DEMO := []u8{
- 120, 218, 101, 144, 65, 110, 131, 48, 16, 69, 215, 246, 41, 190, 44, 69, 73, 32, 148, 182,
- 75, 75, 28, 32, 251, 46, 217, 88, 238, 0, 86, 192, 32, 219, 36, 170, 170, 172, 122, 137,
- 238, 122, 197, 30, 161, 70, 162, 20, 81, 203, 139, 25, 191, 255, 191, 60, 51, 40, 125, 81,
- 53, 33, 144, 15, 156, 155, 110, 232, 93, 128, 208, 189, 35, 89, 117, 65, 112, 222, 41, 99,
- 33, 37, 6, 215, 235, 195, 17, 239, 156, 197, 170, 118, 170, 131, 44, 32, 82, 164, 72, 240,
- 253, 245, 249, 129, 12, 185, 224, 76, 105, 61, 118, 99, 171, 66, 239, 38, 193, 35, 103, 85,
- 172, 66, 127, 33, 139, 24, 244, 235, 141, 49, 204, 223, 76, 208, 205, 204, 166, 7, 173, 60,
- 97, 159, 238, 37, 214, 41, 105, 129, 167, 5, 102, 27, 152, 173, 97, 178, 129, 73, 129, 231,
- 5, 230, 27, 152, 175, 225, 52, 192, 127, 243, 170, 157, 149, 18, 121, 142, 115, 109, 227, 122,
- 64, 87, 114, 111, 161, 49, 182, 6, 181, 158, 162, 226, 206, 167, 27, 215, 246, 48, 56, 99,
- 67, 117, 16, 47, 13, 45, 35, 151, 98, 231, 75, 1, 173, 90, 61, 101, 146, 71, 136, 244,
- 170, 218, 145, 176, 123, 45, 173, 56, 113, 134, 191, 51, 219, 78, 235, 95, 28, 249, 253, 7,
- 159, 150, 133, 125,
- }
- OUTPUT_SIZE :: 432
-
- buf: bytes.Buffer
-
- // We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
- err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
- defer bytes.buffer_destroy(&buf)
-
- if err != nil {
- fmt.printf("\nError: %v\n", err)
- }
- s := bytes.buffer_to_string(&buf)
- fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
- assert(len(s) == OUTPUT_SIZE)
-}
diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin
index 2dc9e81df..be8a7d7d3 100644
--- a/core/compress/zlib/zlib.odin
+++ b/core/compress/zlib/zlib.odin
@@ -1,4 +1,4 @@
-//+vet !using-param
+#+vet !using-param
package compress_zlib
/*
diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin
index b53bacda7..9a76dc78f 100644
--- a/core/container/bit_array/bit_array.odin
+++ b/core/container/bit_array/bit_array.odin
@@ -1,5 +1,6 @@
package container_dynamic_bit_array
+import "base:builtin"
import "base:intrinsics"
import "core:mem"
@@ -18,7 +19,7 @@ NUM_BITS :: 64
Bit_Array :: struct {
bits: [dynamic]u64,
bias: int,
- max_index: int,
+ length: int,
free_pointer: bool,
}
@@ -52,9 +53,9 @@ Returns:
*/
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
- if index > it.array.max_index { return false, 0, false }
+ if index >= it.array.length + it.array.bias { return false, 0, false }
- word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
+ word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
set = (word >> it.bit_idx & 1) == 1
it.bit_idx += 1
@@ -106,22 +107,22 @@ Returns:
*/
@(private="file")
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
- word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
+ word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
when ! ITERATE_SET_BITS { word = ~word }
// If the word is empty or we have already gone over all the bits in it,
// b.bit_idx is greater than the index of any set bit in the word,
// meaning that word >> b.bit_idx == 0.
- for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
+ for it.word_idx < builtin.len(it.array.bits) && word >> it.bit_idx == 0 {
it.word_idx += 1
it.bit_idx = 0
- word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
+ word = it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
when ! ITERATE_SET_BITS { word = ~word }
}
// If we are iterating the set bits, reaching the end of the array means we have no more bits to check
when ITERATE_SET_BITS {
- if it.word_idx >= len(it.array.bits) {
+ if it.word_idx >= builtin.len(it.array.bits) {
return 0, false
}
}
@@ -135,7 +136,7 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
it.bit_idx = 0
it.word_idx += 1
}
- return index, index <= it.array.max_index
+ return index, index < it.array.length + it.array.bias
}
/*
Gets the state of a bit in the bit-array
@@ -160,7 +161,7 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #opti
If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
This early-out prevents unnecessary resizing.
*/
- if leg_index + 1 > len(ba.bits) { return false, true }
+ if leg_index + 1 > builtin.len(ba.bits) { return false, true }
val := u64(1 << uint(bit_index))
res = ba.bits[leg_index] & val == val
@@ -208,7 +209,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator
resize_if_needed(ba, leg_index) or_return
- ba.max_index = max(idx, ba.max_index)
+ ba.length = max(1 + idx, ba.length)
if set_to {
ba.bits[leg_index] |= 1 << uint(bit_index)
@@ -261,6 +262,9 @@ unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
/*
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
+The range of bits created by this procedure is `min_index..<max_index`, and the
+array will be able to expand beyond `max_index` if needed.
+
*Allocates (`new(Bit_Array) & make(ba.bits)`)*
Inputs:
@@ -275,7 +279,7 @@ create :: proc(max_index: int, min_index: int = 0, allocator := context.allocato
context.allocator = allocator
size_in_bits := max_index - min_index
- if size_in_bits < 1 { return {}, false }
+ if size_in_bits < 0 { return {}, false }
legs := size_in_bits >> INDEX_SHIFT
if size_in_bits & INDEX_MASK > 0 {legs+=1}
@@ -284,7 +288,7 @@ create :: proc(max_index: int, min_index: int = 0, allocator := context.allocato
res = new(Bit_Array)
res.bits = bits
res.bias = min_index
- res.max_index = max_index
+ res.length = max_index - min_index
res.free_pointer = true
return
}
@@ -299,6 +303,48 @@ clear :: proc(ba: ^Bit_Array) {
mem.zero_slice(ba.bits[:])
}
/*
+Gets the length of set and unset valid bits in the Bit_Array.
+
+Inputs:
+- ba: The target Bit_Array
+
+Returns:
+- length: The length of valid bits.
+*/
+len :: proc(ba: ^Bit_Array) -> (length: int) {
+ if ba == nil { return }
+ return ba.length
+}
+/*
+Shrinks the Bit_Array's backing storage to the smallest possible size.
+
+Inputs:
+- ba: The target Bit_Array
+*/
+shrink :: proc(ba: ^Bit_Array) #no_bounds_check {
+ if ba == nil { return }
+ legs_needed := builtin.len(ba.bits)
+ for i := legs_needed - 1; i >= 0; i -= 1 {
+ if ba.bits[i] == 0 {
+ legs_needed -= 1
+ } else {
+ break
+ }
+ }
+ if legs_needed == builtin.len(ba.bits) {
+ return
+ }
+ ba.length = 0
+ if legs_needed > 0 {
+ if legs_needed > 1 {
+ ba.length = (legs_needed - 1) * NUM_BITS
+ }
+ ba.length += NUM_BITS - int(intrinsics.count_leading_zeros(ba.bits[legs_needed - 1]))
+ }
+ resize(&ba.bits, legs_needed)
+ builtin.shrink(&ba.bits)
+}
+/*
Deallocates the Bit_Array and its backing storage
Inputs:
@@ -321,8 +367,8 @@ resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocat
context.allocator = allocator
- if legs + 1 > len(ba.bits) {
+ if legs + 1 > builtin.len(ba.bits) {
resize(&ba.bits, legs + 1)
}
- return len(ba.bits) > legs
+ return builtin.len(ba.bits) > legs
}
diff --git a/core/container/bit_array/doc.odin b/core/container/bit_array/doc.odin
index 77e1904a8..36bf90002 100644
--- a/core/container/bit_array/doc.odin
+++ b/core/container/bit_array/doc.odin
@@ -1,8 +1,8 @@
/*
The Bit Array can be used in several ways:
-- By default you don't need to instantiate a Bit Array:
-
+By default you don't need to instantiate a Bit Array.
+Example:
package test
import "core:fmt"
@@ -22,8 +22,8 @@ The Bit Array can be used in several ways:
destroy(&bits)
}
-- A Bit Array can optionally allow for negative indices, if the minimum value was given during creation:
-
+A Bit Array can optionally allow for negative indices, if the minimum value was given during creation.
+Example:
package test
import "core:fmt"
diff --git a/core/container/intrusive/list/doc.odin b/core/container/intrusive/list/doc.odin
index 1a5a12f49..155f1dfe2 100644
--- a/core/container/intrusive/list/doc.odin
+++ b/core/container/intrusive/list/doc.odin
@@ -1,22 +1,22 @@
/*
Package list implements an intrusive doubly-linked list.
-An intrusive container requires a `Node` to be embedded in your own structure, like this:
-
+An intrusive container requires a `Node` to be embedded in your own structure, like this.
+Example:
My_String :: struct {
node: list.Node,
value: string,
}
-Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed:
-
+Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed.
+Example:
My_String :: struct {
using node: list.Node,
value: string,
}
-Here is a full example:
-
+Here is a full example.
+Example:
package test
import "core:fmt"
@@ -42,5 +42,8 @@ Here is a full example:
value: string,
}
+Output:
+ Hello
+ World
*/
package container_intrusive_list
diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin
index b2068469d..77bb21cbc 100644
--- a/core/container/small_array/small_array.odin
+++ b/core/container/small_array/small_array.odin
@@ -139,9 +139,13 @@ clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
resize(a, 0)
}
-push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
- n := copy(a.data[a.len:], items[:])
- a.len += n
+push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) -> bool {
+ if a.len + builtin.len(items) <= cap(a^) {
+ n := copy(a.data[a.len:], items[:])
+ a.len += n
+ return true
+ }
+ return false
}
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
diff --git a/core/crypto/_aes/hw_intel/api.odin b/core/crypto/_aes/hw_intel/api.odin
index 1796bb093..52669cb35 100644
--- a/core/crypto/_aes/hw_intel/api.odin
+++ b/core/crypto/_aes/hw_intel/api.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package aes_hw_intel
import "core:sys/info"
diff --git a/core/crypto/_aes/hw_intel/ghash.odin b/core/crypto/_aes/hw_intel/ghash.odin
index d61e71b3a..4320dd59b 100644
--- a/core/crypto/_aes/hw_intel/ghash.odin
+++ b/core/crypto/_aes/hw_intel/ghash.odin
@@ -20,7 +20,7 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//+build amd64
+#+build amd64
package aes_hw_intel
import "base:intrinsics"
diff --git a/core/crypto/_aes/hw_intel/hw_intel_keysched.odin b/core/crypto/_aes/hw_intel/hw_intel_keysched.odin
index 911dffbd5..bdf0d3066 100644
--- a/core/crypto/_aes/hw_intel/hw_intel_keysched.odin
+++ b/core/crypto/_aes/hw_intel/hw_intel_keysched.odin
@@ -20,7 +20,7 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//+build amd64
+#+build amd64
package aes_hw_intel
import "base:intrinsics"
diff --git a/core/crypto/_chacha20/simd256/chacha20_simd256.odin b/core/crypto/_chacha20/simd256/chacha20_simd256.odin
index 10f2d75fe..ccb02a947 100644
--- a/core/crypto/_chacha20/simd256/chacha20_simd256.odin
+++ b/core/crypto/_chacha20/simd256/chacha20_simd256.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package chacha20_simd256
import "base:intrinsics"
diff --git a/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin b/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin
index 039d6cb96..ce673b42b 100644
--- a/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin
+++ b/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin
@@ -1,4 +1,4 @@
-//+build !amd64
+#+build !amd64
package chacha20_simd256
import "base:intrinsics"
diff --git a/core/crypto/aead/doc.odin b/core/crypto/aead/doc.odin
index 388d31453..93be674a0 100644
--- a/core/crypto/aead/doc.odin
+++ b/core/crypto/aead/doc.odin
@@ -10,49 +10,48 @@ algorithm.
WARNING: Reusing the same key + iv to seal (encrypt) multiple messages
results in catastrophic loss of security for most algorithms.
-```odin
-package aead_example
-
-import "core:bytes"
-import "core:crypto"
-import "core:crypto/aead"
-
-main :: proc() {
- algo := aead.Algorithm.XCHACHA20POLY1305
-
- // The example added associated data, and plaintext.
- aad_str := "Get your ass in gear boys."
- pt_str := "They're immanetizing the Eschaton."
-
- aad := transmute([]byte)aad_str
- plaintext := transmute([]byte)pt_str
- pt_len := len(plaintext)
-
- // Generate a random key for the purposes of illustration.
- key := make([]byte, aead.KEY_SIZES[algo])
- defer delete(key)
- crypto.rand_bytes(key)
-
- // `ciphertext || tag`, is a common way data is transmitted, so
- // demonstrate that.
- buf := make([]byte, pt_len + aead.TAG_SIZES[algo])
- defer delete(buf)
- ciphertext, tag := buf[:pt_len], buf[pt_len:]
-
- // Seal the AAD + Plaintext.
- iv := make([]byte, aead.IV_SIZES[algo])
- defer delete(iv)
- crypto.rand_bytes(iv) // Random IVs are safe with XChaCha20-Poly1305.
- aead.seal(algo, ciphertext, tag, key, iv, aad, plaintext)
-
- // Open the AAD + Ciphertext.
- opened_pt := buf[:pt_len]
- if ok := aead.open(algo, opened_pt, key, iv, aad, ciphertext, tag); !ok {
- panic("aead example: failed to open")
+Example:
+ package aead_example
+
+ import "core:bytes"
+ import "core:crypto"
+ import "core:crypto/aead"
+
+ main :: proc() {
+ algo := aead.Algorithm.XCHACHA20POLY1305
+
+ // The example added associated data, and plaintext.
+ aad_str := "Get your ass in gear boys."
+ pt_str := "They're immanetizing the Eschaton."
+
+ aad := transmute([]byte)aad_str
+ plaintext := transmute([]byte)pt_str
+ pt_len := len(plaintext)
+
+ // Generate a random key for the purposes of illustration.
+ key := make([]byte, aead.KEY_SIZES[algo])
+ defer delete(key)
+ crypto.rand_bytes(key)
+
+ // `ciphertext || tag`, is a common way data is transmitted, so
+ // demonstrate that.
+ buf := make([]byte, pt_len + aead.TAG_SIZES[algo])
+ defer delete(buf)
+ ciphertext, tag := buf[:pt_len], buf[pt_len:]
+
+ // Seal the AAD + Plaintext.
+ iv := make([]byte, aead.IV_SIZES[algo])
+ defer delete(iv)
+ crypto.rand_bytes(iv) // Random IVs are safe with XChaCha20-Poly1305.
+ aead.seal(algo, ciphertext, tag, key, iv, aad, plaintext)
+
+ // Open the AAD + Ciphertext.
+ opened_pt := buf[:pt_len]
+ if ok := aead.open(algo, opened_pt, key, iv, aad, ciphertext, tag); !ok {
+ panic("aead example: failed to open")
+ }
+
+ assert(bytes.equal(opened_pt, plaintext))
}
-
- assert(bytes.equal(opened_pt, plaintext))
-}
-```
*/
-package aead \ No newline at end of file
+package aead
diff --git a/core/crypto/aes/aes.odin b/core/crypto/aes/aes.odin
index ef305fd21..57f49acf4 100644
--- a/core/crypto/aes/aes.odin
+++ b/core/crypto/aes/aes.odin
@@ -2,9 +2,9 @@
package aes implements the AES block cipher and some common modes.
See:
-- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf
-- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
-- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf ]]
+- [[ https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf ]]
+- [[ https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf ]]
*/
package aes
diff --git a/core/crypto/aes/aes_ctr_hw_intel.odin b/core/crypto/aes/aes_ctr_hw_intel.odin
index 1c9e815ad..415758b24 100644
--- a/core/crypto/aes/aes_ctr_hw_intel.odin
+++ b/core/crypto/aes/aes_ctr_hw_intel.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package aes
import "base:intrinsics"
diff --git a/core/crypto/aes/aes_ecb_hw_intel.odin b/core/crypto/aes/aes_ecb_hw_intel.odin
index b2ff36a0c..f1d44a25f 100644
--- a/core/crypto/aes/aes_ecb_hw_intel.odin
+++ b/core/crypto/aes/aes_ecb_hw_intel.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package aes
import "base:intrinsics"
diff --git a/core/crypto/aes/aes_gcm_hw_intel.odin b/core/crypto/aes/aes_gcm_hw_intel.odin
index ffd8ed642..4cb5ab3b2 100644
--- a/core/crypto/aes/aes_gcm_hw_intel.odin
+++ b/core/crypto/aes/aes_gcm_hw_intel.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package aes
import "base:intrinsics"
diff --git a/core/crypto/aes/aes_impl_hw_gen.odin b/core/crypto/aes/aes_impl_hw_gen.odin
index 3557b1aae..0c9ec6edc 100644
--- a/core/crypto/aes/aes_impl_hw_gen.odin
+++ b/core/crypto/aes/aes_impl_hw_gen.odin
@@ -1,4 +1,4 @@
-//+build !amd64
+#+build !amd64
package aes
@(private = "file")
diff --git a/core/crypto/aes/aes_impl_hw_intel.odin b/core/crypto/aes/aes_impl_hw_intel.odin
index 39ea2dc8d..0f1fa6143 100644
--- a/core/crypto/aes/aes_impl_hw_intel.odin
+++ b/core/crypto/aes/aes_impl_hw_intel.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package aes
import "core:crypto/_aes/hw_intel"
diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin
index 384c2ffea..74396b103 100644
--- a/core/crypto/blake2b/blake2b.odin
+++ b/core/crypto/blake2b/blake2b.odin
@@ -2,8 +2,8 @@
package blake2b implements the BLAKE2b hash algorithm.
See:
-- https://datatracker.ietf.org/doc/html/rfc7693
-- https://www.blake2.net
+- [[ https://datatracker.ietf.org/doc/html/rfc7693 ]]
+- [[ https://www.blake2.net ]]
*/
package blake2b
diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin
index 1ba9bef2d..339ddf027 100644
--- a/core/crypto/blake2s/blake2s.odin
+++ b/core/crypto/blake2s/blake2s.odin
@@ -2,8 +2,8 @@
package blake2s implements the BLAKE2s hash algorithm.
See:
-- https://datatracker.ietf.org/doc/html/rfc7693
-- https://www.blake2.net/
+- [[ https://datatracker.ietf.org/doc/html/rfc7693 ]]
+- [[ https://www.blake2.net/ ]]
*/
package blake2s
diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin
index 6d1a6bfc5..dfab2bc65 100644
--- a/core/crypto/chacha20/chacha20.odin
+++ b/core/crypto/chacha20/chacha20.odin
@@ -2,8 +2,8 @@
package chacha20 implements the ChaCha20 and XChaCha20 stream ciphers.
See:
-- https://datatracker.ietf.org/doc/html/rfc8439
-- https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/03/
+- [[ https://datatracker.ietf.org/doc/html/rfc8439 ]]
+- [[ https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/03/ ]]
*/
package chacha20
diff --git a/core/crypto/chacha20poly1305/chacha20poly1305.odin b/core/crypto/chacha20poly1305/chacha20poly1305.odin
index e2cd35a7e..3de2532dd 100644
--- a/core/crypto/chacha20poly1305/chacha20poly1305.odin
+++ b/core/crypto/chacha20poly1305/chacha20poly1305.odin
@@ -4,8 +4,8 @@ AEAD_XChaCha20_Poly1305 Authenticated Encryption with Additional Data
algorithms.
See:
-- https://www.rfc-editor.org/rfc/rfc8439
-- https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03
+- [[ https://www.rfc-editor.org/rfc/rfc8439 ]]
+- [[ https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03 ]]
*/
package chacha20poly1305
diff --git a/core/crypto/ed25519/ed25519.odin b/core/crypto/ed25519/ed25519.odin
index 5584b06f7..460a19563 100644
--- a/core/crypto/ed25519/ed25519.odin
+++ b/core/crypto/ed25519/ed25519.odin
@@ -2,9 +2,9 @@
package ed25519 implements the Ed25519 EdDSA signature algorithm.
See:
-- https://datatracker.ietf.org/doc/html/rfc8032
-- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
-- https://eprint.iacr.org/2020/1244.pdf
+- [[ https://datatracker.ietf.org/doc/html/rfc8032 ]]
+- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf ]]
+- [[ https://eprint.iacr.org/2020/1244.pdf ]]
*/
package ed25519
diff --git a/core/crypto/hash/doc.odin b/core/crypto/hash/doc.odin
index d50908b94..1dfd97de2 100644
--- a/core/crypto/hash/doc.odin
+++ b/core/crypto/hash/doc.odin
@@ -17,46 +17,44 @@ accomplish common tasks.
A third optional boolean parameter controls if the file is streamed
(default), or or read at once.
-```odin
-package hash_example
+Example:
+ package hash_example
-import "core:crypto/hash"
+ import "core:crypto/hash"
-main :: proc() {
- input := "Feed the fire."
+ main :: proc() {
+ input := "Feed the fire."
- // Compute the digest, using the high level API.
- returned_digest := hash.hash(hash.Algorithm.SHA512_256, input)
- defer delete(returned_digest)
+ // Compute the digest, using the high level API.
+ returned_digest := hash.hash(hash.Algorithm.SHA512_256, input)
+ defer delete(returned_digest)
- // Variant that takes a destination buffer, instead of returning
- // the digest.
- digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.BLAKE2B]) // @note: Destination buffer has to be at least as big as the digest size of the hash.
- defer delete(digest)
- hash.hash(hash.Algorithm.BLAKE2B, input, digest)
-}
-```
+ // Variant that takes a destination buffer, instead of returning
+ // the digest.
+ digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.BLAKE2B]) // @note: Destination buffer has to be at least as big as the digest size of the hash.
+ defer delete(digest)
+ hash.hash(hash.Algorithm.BLAKE2B, input, digest)
+ }
A generic low level API is provided supporting the init/update/final interface
that is typical with cryptographic hash function implementations.
-```odin
-package hash_example
+Example:
+ package hash_example
-import "core:crypto/hash"
+ import "core:crypto/hash"
-main :: proc() {
- input := "Let the cinders burn."
+ main :: proc() {
+ input := "Let the cinders burn."
- // Compute the digest, using the low level API.
- ctx: hash.Context
- digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.SHA3_512])
- defer delete(digest)
+ // Compute the digest, using the low level API.
+ ctx: hash.Context
+ digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.SHA3_512])
+ defer delete(digest)
- hash.init(&ctx, hash.Algorithm.SHA3_512)
- hash.update(&ctx, transmute([]byte)input)
- hash.final(&ctx, digest)
-}
-```
+ hash.init(&ctx, hash.Algorithm.SHA3_512)
+ hash.update(&ctx, transmute([]byte)input)
+ hash.final(&ctx, digest)
+ }
*/
-package crypto_hash \ No newline at end of file
+package crypto_hash
diff --git a/core/crypto/hash/hash.odin b/core/crypto/hash/hash.odin
index f7671270a..d47f0ab46 100644
--- a/core/crypto/hash/hash.odin
+++ b/core/crypto/hash/hash.odin
@@ -1,16 +1,15 @@
package crypto_hash
/*
- Copyright 2021 zhibog
- Made available under the BSD-3 license.
+ Copyright 2021 zhibog
+ Made available under the BSD-3 license.
- List of contributors:
- zhibog, dotbmp: Initial implementation.
+ List of contributors:
+ zhibog, dotbmp: Initial implementation.
*/
import "core:io"
import "core:mem"
-import "core:os"
// hash_bytes will hash the given input and return the computed digest
// in a newly allocated slice.
@@ -87,36 +86,3 @@ hash_stream :: proc(
return dst, io.Error.None
}
-
-// hash_file will read the file provided by the given handle and return the
-// computed digest in a newly allocated slice.
-hash_file :: proc(
- algorithm: Algorithm,
- hd: os.Handle,
- load_at_once := false,
- allocator := context.allocator,
-) -> (
- []byte,
- io.Error,
-) {
- if !load_at_once {
- return hash_stream(algorithm, os.stream_from_handle(hd), allocator)
- }
-
- buf, ok := os.read_entire_file(hd, allocator)
- if !ok {
- return nil, io.Error.Unknown
- }
- defer delete(buf, allocator)
-
- return hash_bytes(algorithm, buf, allocator), io.Error.None
-}
-
-hash :: proc {
- hash_stream,
- hash_file,
- hash_bytes,
- hash_string,
- hash_bytes_to_buffer,
- hash_string_to_buffer,
-}
diff --git a/core/crypto/hash/hash_freestanding.odin b/core/crypto/hash/hash_freestanding.odin
new file mode 100644
index 000000000..bec3c4eee
--- /dev/null
+++ b/core/crypto/hash/hash_freestanding.odin
@@ -0,0 +1,10 @@
+#+build freestanding
+package crypto_hash
+
+hash :: proc {
+ hash_stream,
+ hash_bytes,
+ hash_string,
+ hash_bytes_to_buffer,
+ hash_string_to_buffer,
+}
diff --git a/core/crypto/hash/hash_os.odin b/core/crypto/hash/hash_os.odin
new file mode 100644
index 000000000..d54e657ad
--- /dev/null
+++ b/core/crypto/hash/hash_os.odin
@@ -0,0 +1,38 @@
+#+build !freestanding
+package crypto_hash
+
+import "core:io"
+import "core:os"
+
+// hash_file will read the file provided by the given handle and return the
+// computed digest in a newly allocated slice.
+hash_file :: proc(
+ algorithm: Algorithm,
+ hd: os.Handle,
+ load_at_once := false,
+ allocator := context.allocator,
+) -> (
+ []byte,
+ io.Error,
+) {
+ if !load_at_once {
+ return hash_stream(algorithm, os.stream_from_handle(hd), allocator)
+ }
+
+ buf, ok := os.read_entire_file(hd, allocator)
+ if !ok {
+ return nil, io.Error.Unknown
+ }
+ defer delete(buf, allocator)
+
+ return hash_bytes(algorithm, buf, allocator), io.Error.None
+}
+
+hash :: proc {
+ hash_stream,
+ hash_file,
+ hash_bytes,
+ hash_string,
+ hash_bytes_to_buffer,
+ hash_string_to_buffer,
+}
diff --git a/core/crypto/hkdf/hkdf.odin b/core/crypto/hkdf/hkdf.odin
index 2ac67476e..bffe09eff 100644
--- a/core/crypto/hkdf/hkdf.odin
+++ b/core/crypto/hkdf/hkdf.odin
@@ -2,7 +2,7 @@
package hkdf implements the HKDF HMAC-based Extract-and-Expand Key
Derivation Function.
-See: https://www.rfc-editor.org/rfc/rfc5869
+See: [[ https://www.rfc-editor.org/rfc/rfc5869 ]]
*/
package hkdf
diff --git a/core/crypto/hmac/hmac.odin b/core/crypto/hmac/hmac.odin
index 6aac8fca7..4813a9938 100644
--- a/core/crypto/hmac/hmac.odin
+++ b/core/crypto/hmac/hmac.odin
@@ -2,7 +2,7 @@
package hmac implements the HMAC MAC algorithm.
See:
-- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf ]]
*/
package hmac
diff --git a/core/crypto/kmac/kmac.odin b/core/crypto/kmac/kmac.odin
index 711f459b3..e8bf42946 100644
--- a/core/crypto/kmac/kmac.odin
+++ b/core/crypto/kmac/kmac.odin
@@ -2,7 +2,7 @@
package kmac implements the KMAC MAC algorithm.
See:
-- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
*/
package kmac
diff --git a/core/crypto/legacy/md5/md5.odin b/core/crypto/legacy/md5/md5.odin
index c744a9bcf..28b47e0b3 100644
--- a/core/crypto/legacy/md5/md5.odin
+++ b/core/crypto/legacy/md5/md5.odin
@@ -5,8 +5,8 @@ WARNING: The MD5 algorithm is known to be insecure and should only be
used for interoperating with legacy applications.
See:
-- https://eprint.iacr.org/2005/075
-- https://datatracker.ietf.org/doc/html/rfc1321
+- [[ https://eprint.iacr.org/2005/075 ]]
+- [[ https://datatracker.ietf.org/doc/html/rfc1321 ]]
*/
package md5
diff --git a/core/crypto/legacy/sha1/sha1.odin b/core/crypto/legacy/sha1/sha1.odin
index 8c6e59901..1025ecb5b 100644
--- a/core/crypto/legacy/sha1/sha1.odin
+++ b/core/crypto/legacy/sha1/sha1.odin
@@ -5,9 +5,9 @@ WARNING: The SHA1 algorithm is known to be insecure and should only be
used for interoperating with legacy applications.
See:
-- https://eprint.iacr.org/2017/190
-- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
-- https://datatracker.ietf.org/doc/html/rfc3174
+- [[ https://eprint.iacr.org/2017/190 ]]
+- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf ]]
+- [[ https://datatracker.ietf.org/doc/html/rfc3174 ]]
*/
package sha1
diff --git a/core/crypto/pbkdf2/pbkdf2.odin b/core/crypto/pbkdf2/pbkdf2.odin
index 20e490135..8bb5cb73e 100644
--- a/core/crypto/pbkdf2/pbkdf2.odin
+++ b/core/crypto/pbkdf2/pbkdf2.odin
@@ -1,7 +1,7 @@
/*
package pbkdf2 implements the PBKDF2 password-based key derivation function.
-See: https://www.rfc-editor.org/rfc/rfc2898
+See: [[ https://www.rfc-editor.org/rfc/rfc2898 ]]
*/
package pbkdf2
diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin
index 443917a6a..ea0e6c907 100644
--- a/core/crypto/poly1305/poly1305.odin
+++ b/core/crypto/poly1305/poly1305.odin
@@ -2,7 +2,7 @@
package poly1305 implements the Poly1305 one-time MAC algorithm.
See:
-- https://datatracker.ietf.org/doc/html/rfc8439
+- [[ https://datatracker.ietf.org/doc/html/rfc8439 ]]
*/
package poly1305
diff --git a/core/crypto/rand_bsd.odin b/core/crypto/rand_bsd.odin
index 641b72933..78a6fcaaf 100644
--- a/core/crypto/rand_bsd.odin
+++ b/core/crypto/rand_bsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd, openbsd, netbsd
+#+build freebsd, openbsd, netbsd
package crypto
foreign import libc "system:c"
diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin
index 46fb881b3..ef578f5c0 100644
--- a/core/crypto/rand_generic.odin
+++ b/core/crypto/rand_generic.odin
@@ -1,10 +1,10 @@
-//+build !linux
-//+build !windows
-//+build !openbsd
-//+build !freebsd
-//+build !netbsd
-//+build !darwin
-//+build !js
+#+build !linux
+#+build !windows
+#+build !openbsd
+#+build !freebsd
+#+build !netbsd
+#+build !darwin
+#+build !js
package crypto
HAS_RAND_BYTES :: false
diff --git a/core/crypto/ristretto255/ristretto255.odin b/core/crypto/ristretto255/ristretto255.odin
index 3a2307da0..7b0944e33 100644
--- a/core/crypto/ristretto255/ristretto255.odin
+++ b/core/crypto/ristretto255/ristretto255.odin
@@ -2,7 +2,7 @@
package ristretto255 implement the ristretto255 prime-order group.
See:
-- https://www.rfc-editor.org/rfc/rfc9496
+- [[ https://www.rfc-editor.org/rfc/rfc9496 ]]
*/
package ristretto255
diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin
index 2128e3950..4230851ab 100644
--- a/core/crypto/sha2/sha2.odin
+++ b/core/crypto/sha2/sha2.odin
@@ -2,8 +2,8 @@
package sha2 implements the SHA2 hash algorithm family.
See:
-- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
-- https://datatracker.ietf.org/doc/html/rfc3874
+- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf ]]
+- [[ https://datatracker.ietf.org/doc/html/rfc3874 ]]
*/
package sha2
diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin
index 78057f1ca..3b7bdedd7 100644
--- a/core/crypto/sha3/sha3.odin
+++ b/core/crypto/sha3/sha3.odin
@@ -6,7 +6,7 @@ pre-standardization Keccak algorithm is required, it can be found in
crypto/legacy/keccak.
See:
-- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf ]]
*/
package sha3
diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin
index 4160f4cf9..e20795b43 100644
--- a/core/crypto/shake/shake.odin
+++ b/core/crypto/shake/shake.odin
@@ -4,8 +4,8 @@ package shake implements the SHAKE and cSHAKE XOF algorithm families.
The SHA3 hash algorithm can be found in the crypto/sha3.
See:
-- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
-- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf ]]
+- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
*/
package shake
diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin
index c51e38ab0..c145ab3f0 100644
--- a/core/crypto/siphash/siphash.odin
+++ b/core/crypto/siphash/siphash.odin
@@ -1,3 +1,12 @@
+/*
+package siphash Implements the SipHash hashing algorithm.
+
+Use the specific procedures for a certain setup. The generic procedures will default to Siphash 2-4.
+
+See:
+- [[ https://github.com/veorq/SipHash ]]
+- [[ https://www.aumasson.jp/siphash/siphash.pdf ]]
+*/
package siphash
/*
@@ -6,10 +15,6 @@ package siphash
List of contributors:
zhibog: Initial implementation.
-
- Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
-
- Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
*/
import "core:crypto"
diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin
index 2faf37380..f910d735b 100644
--- a/core/crypto/sm3/sm3.odin
+++ b/core/crypto/sm3/sm3.odin
@@ -2,7 +2,7 @@
package sm3 implements the SM3 hash algorithm.
See:
-- https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02
+- [[ https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02 ]]
*/
package sm3
diff --git a/core/crypto/tuplehash/tuplehash.odin b/core/crypto/tuplehash/tuplehash.odin
index ed0a3aa87..e5caaa9c9 100644
--- a/core/crypto/tuplehash/tuplehash.odin
+++ b/core/crypto/tuplehash/tuplehash.odin
@@ -2,7 +2,7 @@
package tuplehash implements the TupleHash and TupleHashXOF algorithms.
See:
-- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
+- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
*/
package tuplehash
diff --git a/core/crypto/x25519/x25519.odin b/core/crypto/x25519/x25519.odin
index f8a301810..412a767b8 100644
--- a/core/crypto/x25519/x25519.odin
+++ b/core/crypto/x25519/x25519.odin
@@ -3,7 +3,7 @@ package x25519 implements the X25519 (aka curve25519) Elliptic-Curve
Diffie-Hellman key exchange protocol.
See:
-- https://www.rfc-editor.org/rfc/rfc7748
+- [[ https://www.rfc-editor.org/rfc/rfc7748 ]]
*/
package x25519
diff --git a/core/debug/trace/trace_cpp.odin b/core/debug/trace/trace_cpp.odin
index dc723184a..8ef377cef 100644
--- a/core/debug/trace/trace_cpp.odin
+++ b/core/debug/trace/trace_cpp.odin
@@ -1,5 +1,5 @@
-//+private file
-//+build linux, darwin
+#+private file
+#+build linux, darwin
package debug_trace
import "base:intrinsics"
diff --git a/core/debug/trace/trace_nil.odin b/core/debug/trace/trace_nil.odin
index 8611d7726..8ee96720e 100644
--- a/core/debug/trace/trace_nil.odin
+++ b/core/debug/trace/trace_nil.odin
@@ -1,4 +1,6 @@
-//+build !windows !linux !darwin
+#+build !windows
+#+build !linux
+#+build !darwin
package debug_trace
import "base:runtime"
diff --git a/core/debug/trace/trace_windows.odin b/core/debug/trace/trace_windows.odin
index de1461e96..c9868e338 100644
--- a/core/debug/trace/trace_windows.odin
+++ b/core/debug/trace/trace_windows.odin
@@ -1,5 +1,5 @@
-//+private
-//+build windows
+#+private
+#+build windows
package debug_trace
import "base:intrinsics"
diff --git a/core/dynlib/doc.odin b/core/dynlib/doc.odin
index f5c91c54e..487fcb715 100644
--- a/core/dynlib/doc.odin
+++ b/core/dynlib/doc.odin
@@ -4,7 +4,6 @@ Package `core:dynlib` implements loading of shared libraries/DLLs and their symb
The behaviour of dynamically loaded libraries is specific to the target platform of the program.
For in depth detail on the underlying behaviour please refer to your target platform's documentation.
-See `example` directory for an example library exporting 3 symbols and a host program loading them automatically
-by defining a symbol table struct.
+For a full example, see: [[ core/dynlib/example; https://github.com/odin-lang/Odin/tree/master/core/dynlib/example ]]
*/
package dynlib
diff --git a/core/dynlib/lib_js.odin b/core/dynlib/lib_js.odin
index bfc724c12..698cfee9c 100644
--- a/core/dynlib/lib_js.odin
+++ b/core/dynlib/lib_js.odin
@@ -1,5 +1,5 @@
-//+build js
-//+private
+#+build js
+#+private
package dynlib
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin
index 8adaadb2d..f467d730d 100644
--- a/core/dynlib/lib_unix.odin
+++ b/core/dynlib/lib_unix.odin
@@ -1,5 +1,5 @@
-//+build linux, darwin, freebsd, openbsd, netbsd
-//+private
+#+build linux, darwin, freebsd, openbsd, netbsd
+#+private
package dynlib
import "core:os"
diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin
index b41abe3b2..6c41a1a75 100644
--- a/core/dynlib/lib_windows.odin
+++ b/core/dynlib/lib_windows.odin
@@ -1,5 +1,5 @@
-//+build windows
-//+private
+#+build windows
+#+private
package dynlib
import win32 "core:sys/windows"
diff --git a/core/encoding/ansi/doc.odin b/core/encoding/ansi/doc.odin
index a0945c581..966e6be00 100644
--- a/core/encoding/ansi/doc.odin
+++ b/core/encoding/ansi/doc.odin
@@ -13,8 +13,8 @@ If your terminal supports 24-bit true color mode, you can also do this:
fmt.println(ansi.CSI + ansi.FG_COLOR_24_BIT + ";0;255;255" + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR)
For more information, see:
- 1. https://en.wikipedia.org/wiki/ANSI_escape_code
- 2. https://www.vt100.net/docs/vt102-ug/chapter5.html
- 3. https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+- [[ https://en.wikipedia.org/wiki/ANSI_escape_code ]]
+- [[ https://www.vt100.net/docs/vt102-ug/chapter5.html ]]
+- [[ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html ]]
*/
package ansi
diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin
index c54660839..bf27171f4 100644
--- a/core/encoding/cbor/unmarshal.odin
+++ b/core/encoding/cbor/unmarshal.odin
@@ -675,10 +675,6 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
return
case reflect.Type_Info_Map:
- if !reflect.is_string(t.key) {
- return _unsupported(v, hdr)
- }
-
raw_map := (^mem.Raw_Map)(v.data)
if raw_map.allocator.procedure == nil {
raw_map.allocator = context.allocator
@@ -695,43 +691,31 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
new_len := uintptr(min(scap, runtime.map_len(raw_map^)+length))
runtime.map_reserve_dynamic(raw_map, t.map_info, new_len) or_return
}
-
- // Temporary memory to unmarshal keys into before inserting them into the map.
+
+ // Temporary memory to unmarshal values into before inserting them into the map.
elem_backing := mem.alloc_bytes_non_zeroed(t.value.size, t.value.align, context.temp_allocator) or_return
defer delete(elem_backing, context.temp_allocator)
-
map_backing_value := any{raw_data(elem_backing), t.value.id}
- for idx := 0; unknown || idx < length; idx += 1 {
- // Decode key, keys can only be strings.
- key: string
- if keyv, kerr := decode_key(d, v); unknown && kerr == .Break {
- break
- } else if kerr != nil {
- err = kerr
- return
- } else {
- key = keyv
- }
+ // Temporary memory to unmarshal keys into.
+ key_backing := mem.alloc_bytes_non_zeroed(t.key.size, t.key.align, context.temp_allocator) or_return
+ defer delete(key_backing, context.temp_allocator)
+ key_backing_value := any{raw_data(key_backing), t.key.id}
+ for idx := 0; unknown || idx < length; idx += 1 {
if unknown || idx > scap {
// Reserve space for new element so we can return allocator errors.
new_len := uintptr(runtime.map_len(raw_map^)+1)
runtime.map_reserve_dynamic(raw_map, t.map_info, new_len) or_return
}
+ mem.zero_slice(key_backing)
+ _unmarshal_value(d, key_backing_value, _decode_header(r) or_return) or_return
+
mem.zero_slice(elem_backing)
_unmarshal_value(d, map_backing_value, _decode_header(r) or_return) or_return
- key_ptr := rawptr(&key)
- key_cstr: cstring
- if reflect.is_cstring(t.key) {
- assert_safe_for_cstring(key)
- key_cstr = cstring(raw_data(key))
- key_ptr = &key_cstr
- }
-
- set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_ptr, map_backing_value.data)
+ set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_backing_value.data, map_backing_value.data)
// We already reserved space for it, so this shouldn't fail.
assert(set_ptr != nil)
}
diff --git a/core/encoding/csv/doc.odin b/core/encoding/csv/doc.odin
new file mode 100644
index 000000000..bfeadafd6
--- /dev/null
+++ b/core/encoding/csv/doc.odin
@@ -0,0 +1,96 @@
+/*
+package csv reads and writes comma-separated values (CSV) files.
+This package supports the format described in [[ RFC 4180; https://tools.ietf.org/html/rfc4180.html ]]
+
+Example:
+ package main
+
+ import "core:fmt"
+ import "core:encoding/csv"
+ import "core:os"
+
+ // Requires keeping the entire CSV file in memory at once
+ iterate_csv_from_string :: proc(filename: string) {
+ r: csv.Reader
+ r.trim_leading_space = true
+ r.reuse_record = true // Without it you have to delete(record)
+ r.reuse_record_buffer = true // Without it you have to each of the fields within it
+ defer csv.reader_destroy(&r)
+
+ csv_data, ok := os.read_entire_file(filename)
+ if ok {
+ csv.reader_init_with_string(&r, string(csv_data))
+ } else {
+ fmt.printfln("Unable to open file: %v", filename)
+ return
+ }
+ defer delete(csv_data)
+
+ for r, i, err in csv.iterator_next(&r) {
+ if err != nil { /* Do something with error */ }
+ for f, j in r {
+ fmt.printfln("Record %v, field %v: %q", i, j, f)
+ }
+ }
+ }
+
+ // Reads the CSV as it's processed (with a small buffer)
+ iterate_csv_from_stream :: proc(filename: string) {
+ fmt.printfln("Hellope from %v", filename)
+ r: csv.Reader
+ r.trim_leading_space = true
+ r.reuse_record = true // Without it you have to delete(record)
+ r.reuse_record_buffer = true // Without it you have to each of the fields within it
+ defer csv.reader_destroy(&r)
+
+ handle, err := os.open(filename)
+ if err != nil {
+ fmt.eprintfln("Error opening file: %v", filename)
+ return
+ }
+ defer os.close(handle)
+ csv.reader_init(&r, os.stream_from_handle(handle))
+
+ for r, i in csv.iterator_next(&r) {
+ for f, j in r {
+ fmt.printfln("Record %v, field %v: %q", i, j, f)
+ }
+ }
+ fmt.printfln("Error: %v", csv.iterator_last_error(r))
+ }
+
+ // Read all records at once
+ read_csv_from_string :: proc(filename: string) {
+ r: csv.Reader
+ r.trim_leading_space = true
+ r.reuse_record = true // Without it you have to delete(record)
+ r.reuse_record_buffer = true // Without it you have to each of the fields within it
+ defer csv.reader_destroy(&r)
+
+ csv_data, ok := os.read_entire_file(filename)
+ if ok {
+ csv.reader_init_with_string(&r, string(csv_data))
+ } else {
+ fmt.printfln("Unable to open file: %v", filename)
+ return
+ }
+ defer delete(csv_data)
+
+ records, err := csv.read_all(&r)
+ if err != nil { /* Do something with CSV parse error */ }
+
+ defer {
+ for rec in records {
+ delete(rec)
+ }
+ delete(records)
+ }
+
+ for r, i in records {
+ for f, j in r {
+ fmt.printfln("Record %v, field %v: %q", i, j, f)
+ }
+ }
+ }
+*/
+package encoding_csv
diff --git a/core/encoding/csv/example.odin b/core/encoding/csv/example.odin
deleted file mode 100644
index d791eb33b..000000000
--- a/core/encoding/csv/example.odin
+++ /dev/null
@@ -1,88 +0,0 @@
-//+build ignore
-package encoding_csv
-
-import "core:fmt"
-import "core:encoding/csv"
-import "core:os"
-
-// Requires keeping the entire CSV file in memory at once
-iterate_csv_from_string :: proc(filename: string) {
- r: csv.Reader
- r.trim_leading_space = true
- r.reuse_record = true // Without it you have to delete(record)
- r.reuse_record_buffer = true // Without it you have to each of the fields within it
- defer csv.reader_destroy(&r)
-
- if csv_data, ok := os.read_entire_file(filename); ok {
- csv.reader_init_with_string(&r, string(csv_data))
- defer delete(csv_data)
- } else {
- fmt.printfln("Unable to open file: %v", filename)
- return
- }
-
- for r, i, err in csv.iterator_next(&r) {
- if err != nil { /* Do something with error */ }
- for f, j in r {
- fmt.printfln("Record %v, field %v: %q", i, j, f)
- }
- }
-}
-
-// Reads the CSV as it's processed (with a small buffer)
-iterate_csv_from_stream :: proc(filename: string) {
- fmt.printfln("Hellope from %v", filename)
- r: csv.Reader
- r.trim_leading_space = true
- r.reuse_record = true // Without it you have to delete(record)
- r.reuse_record_buffer = true // Without it you have to each of the fields within it
- defer csv.reader_destroy(&r)
-
- handle, err := os.open(filename)
- if err != nil {
- fmt.eprintfln("Error opening file: %v", filename)
- return
- }
- defer os.close(handle)
- csv.reader_init(&r, os.stream_from_handle(handle))
-
- for r, i in csv.iterator_next(&r) {
- for f, j in r {
- fmt.printfln("Record %v, field %v: %q", i, j, f)
- }
- }
- fmt.printfln("Error: %v", csv.iterator_last_error(r))
-}
-
-// Read all records at once
-read_csv_from_string :: proc(filename: string) {
- r: csv.Reader
- r.trim_leading_space = true
- r.reuse_record = true // Without it you have to delete(record)
- r.reuse_record_buffer = true // Without it you have to each of the fields within it
- defer csv.reader_destroy(&r)
-
- if csv_data, ok := os.read_entire_file(filename); ok {
- csv.reader_init_with_string(&r, string(csv_data))
- defer delete(csv_data)
- } else {
- fmt.printfln("Unable to open file: %v", filename)
- return
- }
-
- records, err := csv.read_all(&r)
- if err != nil { /* Do something with CSV parse error */ }
-
- defer {
- for rec in records {
- delete(rec)
- }
- delete(records)
- }
-
- for r, i in records {
- for f, j in r {
- fmt.printfln("Record %v, field %v: %q", i, j, f)
- }
- }
-} \ No newline at end of file
diff --git a/core/encoding/csv/reader.odin b/core/encoding/csv/reader.odin
index ebc7b39a0..5348624d5 100644
--- a/core/encoding/csv/reader.odin
+++ b/core/encoding/csv/reader.odin
@@ -1,5 +1,5 @@
// package csv reads and writes comma-separated values (CSV) files.
-// This package supports the format described in RFC 4180 <https://tools.ietf.org/html/rfc4180.html>
+// This package supports the format described in [[ RFC 4180; https://tools.ietf.org/html/rfc4180.html ]]
package encoding_csv
import "core:bufio"
@@ -484,4 +484,4 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
r.fields_per_record = len(dst)
}
return dst[:], err
-} \ No newline at end of file
+}
diff --git a/core/encoding/endian/doc.odin b/core/encoding/endian/doc.odin
index 8ebefd0a4..0b43e3097 100644
--- a/core/encoding/endian/doc.odin
+++ b/core/encoding/endian/doc.odin
@@ -2,22 +2,23 @@
Package endian implements a simple translation between bytes and numbers with
specific endian encodings.
- buf: [100]u8
- put_u16(buf[:], .Little, 16) or_return
+Example:
+ buf: [100]u8
+ put_u16(buf[:], .Little, 16) or_return
- You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write:
- put_u16(buf[:], 16) or_return
+ // You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write:
+ put_u16(buf[:], 16) or_return
- The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of
- each of their fields, or use a header field which specifies it for the entire file.
+ // The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of
+ // each of their fields, or use a header field which specifies it for the entire file.
- e.g. a file which specifies it at the top for all fields could do this:
- file_order := .Little if buf[0] == 0 else .Big
- field := get_u16(buf[1:], file_order) or_return
+ // e.g. a file which specifies it at the top for all fields could do this:
+ file_order := .Little if buf[0] == 0 else .Big
+ field := get_u16(buf[1:], file_order) or_return
- If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader,
- be that your future self or someone else.
+ // If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader,
+ // be that your future self or someone else.
- field := get_u16(buf[:], .Big) or_return
+ field := get_u16(buf[:], .Big) or_return
*/
package encoding_endian
diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin
index f5208ad6f..d2f1d46b2 100644
--- a/core/encoding/entity/entity.odin
+++ b/core/encoding/entity/entity.odin
@@ -1,23 +1,25 @@
-package encoding_unicode_entity
/*
- A unicode entity encoder/decoder
-
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
+ List of contributors:
+ Jeroen van Rijn: Initial implementation.
+*/
+
+/*
+ A unicode entity encoder/decoder.
+
This code has several procedures to map unicode runes to/from different textual encodings.
- SGML/XML/HTML entity
- -- &#<decimal>;
- -- &#x<hexadecimal>;
- -- &<entity name>; (If the lookup tables are compiled in).
- Reference: https://www.w3.org/2003/entities/2007xml/unicode.xml
+ - &#<decimal>;
+ - &#x<hexadecimal>;
+ - &<entity name>; (If the lookup tables are compiled in).
+ Reference: [[ https://www.w3.org/2003/entities/2007xml/unicode.xml ]]
- URL encode / decode %hex entity
- Reference: https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1
-
- List of contributors:
- Jeroen van Rijn: Initial implementation.
+ Reference: [[ https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1 ]]
*/
+package encoding_unicode_entity
import "core:unicode/utf8"
import "core:unicode"
@@ -353,4 +355,4 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
}
return false, .None
-} \ No newline at end of file
+}
diff --git a/core/encoding/entity/generated.odin b/core/encoding/entity/generated.odin
index 0c4742149..52027ae03 100644
--- a/core/encoding/entity/generated.odin
+++ b/core/encoding/entity/generated.odin
@@ -42,7 +42,7 @@ XML_NAME_TO_RUNE_MAX_LENGTH :: 31
Input:
entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML.
- Output:
+ Returns:
"decoded" - The decoded rune if found by name, or -1 otherwise.
"ok" - true if found, false if not.
diff --git a/core/encoding/hxa/doc.odin b/core/encoding/hxa/doc.odin
index 230d6ea66..b696bef7e 100644
--- a/core/encoding/hxa/doc.odin
+++ b/core/encoding/hxa/doc.odin
@@ -1,83 +1,89 @@
-// Implementation of the HxA 3D asset format
-// HxA is a interchangeable graphics asset format.
-// Designed by Eskil Steenberg. @quelsolaar / eskil 'at' obsession 'dot' se / www.quelsolaar.com
-//
-// Author of this Odin package: Ginger Bill
-//
-// Following comment is copied from the original C-implementation
-// ---------
-// -Does the world need another Graphics file format?
-// Unfortunately, Yes. All existing formats are either too large and complicated to be implemented from
-// scratch, or don't have some basic features needed in modern computer graphics.
-// -Who is this format for?
-// For people who want a capable open Graphics format that can be implemented from scratch in
-// a few hours. It is ideal for graphics researchers, game developers or other people who
-// wants to build custom graphics pipelines. Given how easy it is to parse and write, it
-// should be easy to write utilities that process assets to preform tasks like: generating
-// normals, light-maps, tangent spaces, Error detection, GPU optimization, LOD generation,
-// and UV mapping.
-// -Why store images in the format when there are so many good image formats already?
-// Yes there are, but only for 2D RGB/RGBA images. A lot of computer graphics rendering rely
-// on 1D, 3D, cube, multilayer, multi channel, floating point bitmap buffers. There almost no
-// formats for this kind of data. Also 3D files that reference separate image files rely on
-// file paths, and this often creates issues when the assets are moved. By including the
-// texture data in the files directly the assets become self contained.
-// -Why doesn't the format support <insert whatever>?
-// Because the entire point is to make a format that can be implemented. Features like NURBSs,
-// Construction history, or BSP trees would make the format too large to serve its purpose.
-// The facilities of the formats to store meta data should make the format flexible enough
-// for most uses. Adding HxA support should be something anyone can do in a days work.
-//
-// Structure:
-// ----------
-// HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
-// a few basic structures, and depending on how they are used they mean different things. This means
-// that you can implement a tool that loads the entire file, modifies the parts it cares about and
-// leaves the rest intact. It is also possible to write a tool that makes all data in the file
-// editable without the need to understand its use. It is also possible for anyone to use the format
-// to store data axillary data. Anyone who wants to store data not covered by a convention can submit
-// a convention to extend the format. There should never be a convention for storing the same data in
-// two differed ways.
-// The data is story in a number of nodes that are stored in an array. Each node stores an array of
-// meta data. Meta data can describe anything you want, and a lot of conventions will use meta data
-// to store additional information, for things like transforms, lights, shaders and animation.
-// Data for Vertices, Corners, Faces, and Pixels are stored in named layer stacks. Each stack consists
-// of a number of named layers. All layers in the stack have the same number of elements. Each layer
-// describes one property of the primitive. Each layer can have multiple channels and each layer can
-// store data of a different type.
-//
-// HaX stores 3 kinds of nodes
-// - Pixel data.
-// - Polygon geometry data.
-// - Meta data only.
-//
-// Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
-// Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
-// layers to store things like color. The length of the layer stack is determined by the type and
-// dimensions stored in the
-//
-// Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
-// vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
-// layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
-// of the vertices. The corner stack describes data per corner or edge of the polygons. It can be used
-// for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
-// integer layer named "index" describing the vertices used to form polygons. The last value in each
-// polygon has a negative - 1 index to indicate the end of the polygon.
-//
-// Example:
-// A quad and a tri with the vertex index:
-// [0, 1, 2, 3] [1, 4, 2]
-// is stored:
-// [0, 1, 2, -4, 1, 4, -3]
-// The face stack stores values per face. the length of the face stack has to match the number of
-// negative values in the index layer in the corner stack. The face stack can be used to store things
-// like material index.
-//
-// Storage
-// -------
-// All data is stored in little endian byte order with no padding. The layout mirrors the structs
-// defined below with a few exceptions. All names are stored as a 8-bit unsigned integer indicating
-// the length of the name followed by that many characters. Termination is not stored in the file.
-// Text strings stored in meta data are stored the same way as names, but instead of a 8-bit unsigned
-// integer a 32-bit unsigned integer is used.
-package encoding_hxa \ No newline at end of file
+/*
+Implementation of the HxA 3D asset format
+HxA is a interchangeable graphics asset format.
+Designed by Eskil Steenberg. @quelsolaar / eskil 'at' obsession 'dot' se / www.quelsolaar.com
+
+Author of this Odin package: Ginger Bill
+
+Following comment is copied from the original C-implementation
+---------
+- Does the world need another Graphics file format?
+Unfortunately, Yes. All existing formats are either too large and complicated to be implemented from
+scratch, or don't have some basic features needed in modern computer graphics.
+
+- Who is this format for?
+For people who want a capable open Graphics format that can be implemented from scratch in
+a few hours. It is ideal for graphics researchers, game developers or other people who
+wants to build custom graphics pipelines. Given how easy it is to parse and write, it
+should be easy to write utilities that process assets to preform tasks like: generating
+normals, light-maps, tangent spaces, Error detection, GPU optimization, LOD generation,
+and UV mapping.
+
+- Why store images in the format when there are so many good image formats already?
+Yes there are, but only for 2D RGB/RGBA images. A lot of computer graphics rendering rely
+on 1D, 3D, cube, multilayer, multi channel, floating point bitmap buffers. There almost no
+formats for this kind of data. Also 3D files that reference separate image files rely on
+file paths, and this often creates issues when the assets are moved. By including the
+texture data in the files directly the assets become self contained.
+
+- Why doesn't the format support <insert whatever>?
+Because the entire point is to make a format that can be implemented. Features like NURBSs,
+Construction history, or BSP trees would make the format too large to serve its purpose.
+The facilities of the formats to store meta data should make the format flexible enough
+for most uses. Adding HxA support should be something anyone can do in a days work.
+
+Structure:
+----------
+HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
+a few basic structures, and depending on how they are used they mean different things. This means
+that you can implement a tool that loads the entire file, modifies the parts it cares about and
+leaves the rest intact. It is also possible to write a tool that makes all data in the file
+editable without the need to understand its use. It is also possible for anyone to use the format
+to store data axillary data. Anyone who wants to store data not covered by a convention can submit
+a convention to extend the format. There should never be a convention for storing the same data in
+two differed ways.
+
+The data is story in a number of nodes that are stored in an array. Each node stores an array of
+meta data. Meta data can describe anything you want, and a lot of conventions will use meta data
+to store additional information, for things like transforms, lights, shaders and animation.
+Data for Vertices, Corners, Faces, and Pixels are stored in named layer stacks. Each stack consists
+of a number of named layers. All layers in the stack have the same number of elements. Each layer
+describes one property of the primitive. Each layer can have multiple channels and each layer can
+store data of a different type.
+
+HaX stores 3 kinds of nodes
+- Pixel data.
+- Polygon geometry data.
+- Meta data only.
+
+Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
+Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
+layers to store things like color.
+The length of the layer stack is determined by the type and dimensions stored in the Geometry data
+is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
+vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
+layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
+of the vertices. The corner stack describes data per corner or edge of the polygons. It can be used
+for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
+integer layer named "index" describing the vertices used to form polygons. The last value in each
+polygon has a negative - 1 index to indicate the end of the polygon.
+
+For Example:
+ A quad and a tri with the vertex index:
+ [0, 1, 2, 3] [1, 4, 2]
+ is stored:
+ [0, 1, 2, -4, 1, 4, -3]
+
+The face stack stores values per face. the length of the face stack has to match the number of
+negative values in the index layer in the corner stack. The face stack can be used to store things
+like material index.
+
+Storage:
+-------
+All data is stored in little endian byte order with no padding. The layout mirrors the structs
+defined below with a few exceptions. All names are stored as a 8-bit unsigned integer indicating
+the length of the name followed by that many characters. Termination is not stored in the file.
+Text strings stored in meta data are stored the same way as names, but instead of a 8-bit unsigned
+integer a 32-bit unsigned integer is used.
+*/
+package encoding_hxa
diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin
index 127bce650..738e20c68 100644
--- a/core/encoding/json/unmarshal.odin
+++ b/core/encoding/json/unmarshal.odin
@@ -116,7 +116,30 @@ assign_int :: proc(val: any, i: $T) -> bool {
case int: dst = int (i)
case uint: dst = uint (i)
case uintptr: dst = uintptr(i)
- case: return false
+ case:
+ ti := type_info_of(v.id)
+ if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok {
+ do_byte_swap := !reflect.bit_set_is_big_endian(v)
+ switch ti.size * 8 {
+ case 0: // no-op.
+ case 8:
+ x := (^u8)(v.data)
+ x^ = u8(i)
+ case 16:
+ x := (^u16)(v.data)
+ x^ = do_byte_swap ? intrinsics.byte_swap(u16(i)) : u16(i)
+ case 32:
+ x := (^u32)(v.data)
+ x^ = do_byte_swap ? intrinsics.byte_swap(u32(i)) : u32(i)
+ case 64:
+ x := (^u64)(v.data)
+ x^ = do_byte_swap ? intrinsics.byte_swap(u64(i)) : u64(i)
+ case:
+ panic("unknown bit_size size")
+ }
+ return true
+ }
+ return false
}
return true
}
diff --git a/core/encoding/uuid/doc.odin b/core/encoding/uuid/doc.odin
index 6fa375b72..f910c33d8 100644
--- a/core/encoding/uuid/doc.odin
+++ b/core/encoding/uuid/doc.odin
@@ -21,8 +21,9 @@ cryptographically-secure, per RFC 9562's suggestion.
- Version 6 without either a clock or node argument.
- Version 7 in all cases.
-Here's an example of how to set up one:
-
+Example:
+ package main
+
import "core:crypto"
import "core:encoding/uuid"
@@ -40,7 +41,7 @@ Here's an example of how to set up one:
For more information on the specifications, see here:
-- https://www.rfc-editor.org/rfc/rfc4122.html
-- https://www.rfc-editor.org/rfc/rfc9562.html
+- [[ https://www.rfc-editor.org/rfc/rfc4122.html ]]
+- [[ https://www.rfc-editor.org/rfc/rfc9562.html ]]
*/
package uuid
diff --git a/core/encoding/uuid/writing.odin b/core/encoding/uuid/writing.odin
index 499cba72b..7acaa3cd7 100644
--- a/core/encoding/uuid/writing.odin
+++ b/core/encoding/uuid/writing.odin
@@ -11,7 +11,7 @@ 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
+UUID (36 bytes), then it is better to use `unsafe_write` instead as that will
be faster.
Inputs:
@@ -22,7 +22,7 @@ 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 {
+ write_octet :: proc(w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
high_nibble := octet >> 4
low_nibble := octet & 0xF
@@ -31,15 +31,15 @@ write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_chec
return nil
}
- for index in 0 ..< 4 { write_octet(w, id[index]) or_return }
+ 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 }
+ 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 }
+ 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 }
+ 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 }
+ for index in 10 ..< 16 {write_octet(w, id[index]) or_return}
return nil
}
@@ -54,7 +54,7 @@ Inputs:
- 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 {
+ write_octet :: proc(w: io.Writer, octet: u8) #no_bounds_check {
high_nibble := octet >> 4
low_nibble := octet & 0xF
@@ -62,15 +62,15 @@ unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
io.write_byte(w, strconv.digits[low_nibble])
}
- for index in 0 ..< 4 { write_octet(w, id[index]) }
+ for index in 0 ..< 4 {write_octet(w, id[index])}
io.write_byte(w, '-')
- for index in 4 ..< 6 { write_octet(w, id[index]) }
+ for index in 4 ..< 6 {write_octet(w, id[index])}
io.write_byte(w, '-')
- for index in 6 ..< 8 { write_octet(w, id[index]) }
+ for index in 6 ..< 8 {write_octet(w, id[index])}
io.write_byte(w, '-')
- for index in 8 ..< 10 { write_octet(w, id[index]) }
+ for index in 8 ..< 10 {write_octet(w, id[index])}
io.write_byte(w, '-')
- for index in 10 ..< 16 { write_octet(w, id[index]) }
+ for index in 10 ..< 16 {write_octet(w, id[index])}
}
/*
@@ -106,7 +106,7 @@ 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.
+- buffer: A byte buffer to store the result. Must be at least 36 bytes large.
- loc: The caller location for debugging purposes (default: #caller_location)
Returns:
@@ -119,7 +119,11 @@ to_string_buffer :: proc(
) -> (
str: string,
) {
- assert(len(buffer) >= EXPECTED_LENGTH, "The buffer provided is not at least 32 bytes large.", loc)
+ assert(
+ len(buffer) >= EXPECTED_LENGTH,
+ "The buffer provided is not at least 36 bytes large.",
+ loc,
+ )
builder := strings.builder_from_bytes(buffer)
unsafe_write(strings.to_writer(&builder), id)
return strings.to_string(builder)
@@ -129,3 +133,4 @@ to_string :: proc {
to_string_allocated,
to_string_buffer,
}
+
diff --git a/core/encoding/varint/doc.odin b/core/encoding/varint/doc.odin
index c0a09873c..a00cfed15 100644
--- a/core/encoding/varint/doc.odin
+++ b/core/encoding/varint/doc.odin
@@ -1,10 +1,11 @@
/*
- Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
+Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
- Author of this Odin package: Jeroen van Rijn
+Author of this Odin package: Jeroen van Rijn
+
+Example:
+ package main
- Example:
- ```odin
import "core:encoding/varint"
import "core:fmt"
@@ -22,7 +23,5 @@
assert(decoded_val == value && decode_size == encode_size && decode_err == .None)
fmt.printf("Decoded as %v, using %v byte%v\n", decoded_val, decode_size, "" if decode_size == 1 else "s")
}
- ```
-
*/
-package encoding_varint \ No newline at end of file
+package encoding_varint
diff --git a/core/encoding/varint/leb128.odin b/core/encoding/varint/leb128.odin
index ca6513f04..606c57ba7 100644
--- a/core/encoding/varint/leb128.odin
+++ b/core/encoding/varint/leb128.odin
@@ -6,8 +6,6 @@
Jeroen van Rijn: Initial implementation.
*/
-// package varint implements variable length integer encoding and decoding using
-// the LEB128 format as used by DWARF debug info, Android .dex and other file formats.
package encoding_varint
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
@@ -160,4 +158,4 @@ encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) {
buf[size - 1] = u8(low)
}
return
-} \ No newline at end of file
+}
diff --git a/core/encoding/xml/doc.odin b/core/encoding/xml/doc.odin
new file mode 100644
index 000000000..10d9f78be
--- /dev/null
+++ b/core/encoding/xml/doc.odin
@@ -0,0 +1,23 @@
+/*
+XML 1.0 / 1.1 parser
+
+A from-scratch XML implementation, loosely modelled on the [[ spec; https://www.w3.org/TR/2006/REC-xml11-20060816 ]].
+
+Features:
+- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
+- Simple to understand and use. Small.
+
+Caveats:
+- We do NOT support HTML in this package, as that may or may not be valid XML.
+ If it works, great. If it doesn't, that's not considered a bug.
+
+- We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences.
+- <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options.
+
+MAYBE:
+- XML writer?
+- Serialize/deserialize Odin types?
+
+For a full example, see: [[ core/encoding/xml/example; https://github.com/odin-lang/Odin/tree/master/core/encoding/xml/example ]]
+*/
+package encoding_xml
diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin
index b9656900f..b8c8b13a4 100644
--- a/core/encoding/xml/xml_reader.odin
+++ b/core/encoding/xml/xml_reader.odin
@@ -1,29 +1,11 @@
/*
- XML 1.0 / 1.1 parser
+ 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
+ available under Odin's BSD-3 license.
- 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
- available under Odin's BSD-3 license.
-
- from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
-
-Features:
-- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
-- Simple to understand and use. Small.
-
-Caveats:
-- We do NOT support HTML in this package, as that may or may not be valid XML.
- If it works, great. If it doesn't, that's not considered a bug.
-
-- We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences.
-- <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options.
-
-MAYBE:
-- XML writer?
-- Serialize/deserialize Odin types?
-
-List of contributors:
-- Jeroen van Rijn: Initial implementation.
+ List of contributors:
+ - Jeroen van Rijn: Initial implementation.
*/
+
package encoding_xml
// An XML 1.0 / 1.1 parser
diff --git a/core/flags/doc.odin b/core/flags/doc.odin
index c3663c419..b97547806 100644
--- a/core/flags/doc.odin
+++ b/core/flags/doc.odin
@@ -11,15 +11,13 @@ 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
------------- ------------------------
-<positional> depends on struct layout
--<flag> set a bool true
--<flag:option> set flag to option
--<flag=option> set flag to option, alternative syntax
--<map>:<key>=<value> set map[key] to value
-```
+ type handling
+ ------------ ------------------------
+ <positional> depends on struct layout
+ -<flag> set a bool true
+ -<flag:option> set flag to option
+ -<flag=option> set flag to option, alternative syntax
+ -<map>:<key>=<value> set map[key] to value
Struct Tags:
@@ -40,11 +38,9 @@ Under the `args` tag, there are the following subtags:
- `indistinct`: allow the setting of distinct types by their base type.
`required` may be given a range specifier in the following formats:
-```
-min
-<max
-min<max
-```
+ min
+ <max
+ min<max
`max` is not inclusive in this range, as noted by the less-than `<` sign, so if
you want to require 3 and only 3 arguments in a dynamic array, you would
@@ -161,21 +157,15 @@ UNIX-style:
This package also supports parsing arguments in a limited flavor of UNIX.
Odin and UNIX style are mutually exclusive, and which one to be used is chosen
at parse time.
-
-```
---flag
---flag=argument
---flag argument
---flag argument repeating-argument
-```
+ --flag
+ --flag=argument
+ --flag argument
+ --flag argument repeating-argument
`-flag` may also be substituted for `--flag`.
Do note that map flags are not currently supported in this parsing style.
-
-Example:
-
-A complete example is given in the `example` subdirectory.
+For a complete example, see: [[ core/flags/example; https://github.com/odin-lang/Odin/blob/master/core/flags/example/example.odin ]].
*/
package flags
diff --git a/core/flags/errors_bsd.odin b/core/flags/errors_bsd.odin
index 1fe6de90b..4d98d2ee4 100644
--- a/core/flags/errors_bsd.odin
+++ b/core/flags/errors_bsd.odin
@@ -1,4 +1,4 @@
-//+build netbsd, openbsd
+#+build netbsd, openbsd
package flags
import "base:runtime"
diff --git a/core/flags/errors_nonbsd.odin b/core/flags/errors_nonbsd.odin
index a77f12abf..28912b57f 100644
--- a/core/flags/errors_nonbsd.odin
+++ b/core/flags/errors_nonbsd.odin
@@ -1,4 +1,5 @@
-//+build !netbsd !openbsd
+#+build !netbsd
+#+build !openbsd
package flags
import "base:runtime"
diff --git a/core/flags/internal_assignment.odin b/core/flags/internal_assignment.odin
index bb49977eb..12ddb876f 100644
--- a/core/flags/internal_assignment.odin
+++ b/core/flags/internal_assignment.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package flags
import "base:intrinsics"
@@ -14,10 +14,10 @@ import "core:reflect"
// 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.
+ if set, valid_index := bit_array.get(&parser.filled_pos, parser.filled_pos.length - 1); set || !valid_index {
+ // The index below the last one is either set or invalid, 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)
+ bit_array.set(&parser.filled_pos, parser.filled_pos.length, false)
}
pos: int = ---
diff --git a/core/flags/internal_parsing.odin b/core/flags/internal_parsing.odin
index 7a769b17c..4e49f45b0 100644
--- a/core/flags/internal_parsing.odin
+++ b/core/flags/internal_parsing.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package flags
import "core:container/bit_array"
diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin
index 4c1db5d0b..1c559ca55 100644
--- a/core/flags/internal_rtti.odin
+++ b/core/flags/internal_rtti.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package flags
import "base:intrinsics"
diff --git a/core/flags/internal_rtti_nonbsd.odin b/core/flags/internal_rtti_nonbsd.odin
index 27fdb3b75..e1286186b 100644
--- a/core/flags/internal_rtti_nonbsd.odin
+++ b/core/flags/internal_rtti_nonbsd.odin
@@ -1,5 +1,6 @@
-//+private
-//+build !netbsd !openbsd
+#+private
+#+build !netbsd
+#+build !openbsd
package flags
import "core:net"
diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin
index b71cf9fe7..afd05331c 100644
--- a/core/flags/internal_validation.odin
+++ b/core/flags/internal_validation.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package flags
@require import "base:runtime"
diff --git a/core/fmt/example.odin b/core/fmt/example.odin
index 503e64f2b..6929e9be7 100644
--- a/core/fmt/example.odin
+++ b/core/fmt/example.odin
@@ -1,4 +1,4 @@
-//+build ignore
+#+build ignore
package custom_formatter_example
import "core:fmt"
import "core:io"
diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin
index acf218eb5..ce90fbfe7 100644
--- a/core/fmt/fmt_js.odin
+++ b/core/fmt/fmt_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package fmt
import "core:bufio"
diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin
index 9de0d43be..a481061f1 100644
--- a/core/fmt/fmt_os.odin
+++ b/core/fmt/fmt_os.odin
@@ -1,6 +1,6 @@
-//+build !freestanding
-//+build !js
-//+build !orca
+#+build !freestanding
+#+build !js
+#+build !orca
package fmt
import "base:runtime"
diff --git a/core/hash/xxhash/common.odin b/core/hash/xxhash/common.odin
index bbeb60db3..adfc1bac2 100644
--- a/core/hash/xxhash/common.odin
+++ b/core/hash/xxhash/common.odin
@@ -1,5 +1,4 @@
/*
- An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
@@ -7,6 +6,8 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
+
+// An implementation of Yann Collet's [[ xxhash Fast Hash Algorithm; https://cyan4973.github.io/xxHash/ ]].
package xxhash
import "base:intrinsics"
diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin
index f68862f67..f77edf3e9 100644
--- a/core/hash/xxhash/streaming.odin
+++ b/core/hash/xxhash/streaming.odin
@@ -7,6 +7,7 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
+
package xxhash
import "core:mem"
@@ -371,4 +372,4 @@ XXH3_generate_secret :: proc(secret_buffer: []u8, custom_seed: []u8) {
mem_copy(&secret_buffer[segment_start], &segment, size_of(segment))
}
}
-} \ No newline at end of file
+}
diff --git a/core/hash/xxhash/xxhash_3.odin b/core/hash/xxhash/xxhash_3.odin
index 9e159260b..293e98528 100644
--- a/core/hash/xxhash/xxhash_3.odin
+++ b/core/hash/xxhash/xxhash_3.odin
@@ -7,6 +7,7 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
+
package xxhash
import "base:intrinsics"
diff --git a/core/hash/xxhash/xxhash_32.odin b/core/hash/xxhash/xxhash_32.odin
index 3ea1c3cf2..28cd4e177 100644
--- a/core/hash/xxhash/xxhash_32.odin
+++ b/core/hash/xxhash/xxhash_32.odin
@@ -7,6 +7,7 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
+
package xxhash
import "base:intrinsics"
diff --git a/core/hash/xxhash/xxhash_64.odin b/core/hash/xxhash/xxhash_64.odin
index 3b24f20a1..87e8916d6 100644
--- a/core/hash/xxhash/xxhash_64.odin
+++ b/core/hash/xxhash/xxhash_64.odin
@@ -7,6 +7,7 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
+
package xxhash
import "base:intrinsics"
@@ -19,15 +20,15 @@ xxh_u64 :: u64
XXH64_DEFAULT_SEED :: XXH64_hash(0)
XXH64_state :: struct {
- total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */
- v1: XXH64_hash, /*!< First accumulator lane */
- v2: XXH64_hash, /*!< Second accumulator lane */
- v3: XXH64_hash, /*!< Third accumulator lane */
- v4: XXH64_hash, /*!< Fourth accumulator lane */
- mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
- memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */
- reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/
- reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */
+ total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */
+ v1: XXH64_hash, /*!< First accumulator lane */
+ v2: XXH64_hash, /*!< Second accumulator lane */
+ v3: XXH64_hash, /*!< Third accumulator lane */
+ v4: XXH64_hash, /*!< Fourth accumulator lane */
+ mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
+ memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */
+ reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/
+ reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */
}
XXH64_canonical :: struct {
diff --git a/core/image/bmp/bmp_js.odin b/core/image/bmp/bmp_js.odin
index d87a7d2d5..fa5d59095 100644
--- a/core/image/bmp/bmp_js.odin
+++ b/core/image/bmp/bmp_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package core_image_bmp
load :: proc{load_from_bytes, load_from_context}
diff --git a/core/image/bmp/bmp_os.odin b/core/image/bmp/bmp_os.odin
index d20abc685..70a85a784 100644
--- a/core/image/bmp/bmp_os.odin
+++ b/core/image/bmp/bmp_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package core_image_bmp
import "core:os"
diff --git a/core/image/common.odin b/core/image/common.odin
index 62deb60a9..690ebc045 100644
--- a/core/image/common.odin
+++ b/core/image/common.odin
@@ -1393,6 +1393,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
for p in inp {
out[0].rgb = p.r // Gray component.
out[0].a = p.g // Alpha component.
+ out = out[1:]
}
case:
@@ -1417,6 +1418,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
for p in inp {
out[0].rgb = p.r // Gray component.
out[0].a = p.g // Alpha component.
+ out = out[1:]
}
case:
diff --git a/core/image/general_js.odin b/core/image/general_js.odin
index 841d9c200..abf9812c0 100644
--- a/core/image/general_js.odin
+++ b/core/image/general_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package image
load :: proc{
diff --git a/core/image/general_os.odin b/core/image/general_os.odin
index e1fe440a4..98eb5bdbe 100644
--- a/core/image/general_os.odin
+++ b/core/image/general_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package image
import "core:os"
diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin
index ab3945ad7..a9dc6599a 100644
--- a/core/image/netpbm/netpbm.odin
+++ b/core/image/netpbm/netpbm.odin
@@ -1,4 +1,4 @@
-//+vet !using-stmt
+#+vet !using-stmt
package netpbm
import "core:bytes"
diff --git a/core/image/netpbm/netpbm_js.odin b/core/image/netpbm/netpbm_js.odin
index 7db17a05d..7d475cf62 100644
--- a/core/image/netpbm/netpbm_js.odin
+++ b/core/image/netpbm/netpbm_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package netpbm
load :: proc {
diff --git a/core/image/netpbm/netpbm_os.odin b/core/image/netpbm/netpbm_os.odin
index 609f1ea1f..2cf2439ac 100644
--- a/core/image/netpbm/netpbm_os.odin
+++ b/core/image/netpbm/netpbm_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package netpbm
import "core:os"
diff --git a/core/image/png/doc.odin b/core/image/png/doc.odin
new file mode 100644
index 000000000..623c13077
--- /dev/null
+++ b/core/image/png/doc.odin
@@ -0,0 +1,348 @@
+/*
+package png implements a PNG image reader
+
+The PNG specification is at [[ https://www.w3.org/TR/PNG/ ]].
+
+Example:
+ package main
+
+ import "core:image"
+ // import "core:image/png"
+ import "core:bytes"
+ import "core:fmt"
+
+ // For PPM writer
+ import "core:mem"
+ import "core:os"
+
+ main :: proc() {
+ track := mem.Tracking_Allocator{}
+ mem.tracking_allocator_init(&track, context.allocator)
+
+ context.allocator = mem.tracking_allocator(&track)
+
+ demo()
+
+ if len(track.allocation_map) > 0 {
+ fmt.println("Leaks:")
+ for _, v in track.allocation_map {
+ fmt.printf("\t%v\n\n", v)
+ }
+ }
+ }
+
+ demo :: proc() {
+ file: string
+
+ options := image.Options{.return_metadata}
+ err: image.Error
+ img: ^image.Image
+
+ file = "../../../misc/logo-slim.png"
+
+ img, err = load(file, options)
+ defer destroy(img)
+
+ if err != nil {
+ fmt.printf("Trying to read PNG file %v returned %v\n", file, err)
+ } else {
+ fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth)
+
+ if v, ok := img.metadata.(^image.PNG_Info); ok {
+ // Handle ancillary chunks as you wish.
+ // We provide helper functions for a few types.
+ for c in v.chunks {
+ #partial switch c.header.type {
+ case .tIME:
+ if t, t_ok := core_time(c); t_ok {
+ fmt.printf("[tIME]: %v\n", t)
+ }
+ case .gAMA:
+ if gama, gama_ok := gamma(c); gama_ok {
+ fmt.printf("[gAMA]: %v\n", gama)
+ }
+ case .pHYs:
+ if phys, phys_ok := phys(c); phys_ok {
+ if phys.unit == .Meter {
+ xm := f32(img.width) / f32(phys.ppu_x)
+ ym := f32(img.height) / f32(phys.ppu_y)
+ dpi_x, dpi_y := phys_to_dpi(phys)
+ fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y)
+ fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y)
+ fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym)
+ } else {
+ fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y)
+ }
+ }
+ case .iTXt, .zTXt, .tEXt:
+ res, ok_text := text(c)
+ if ok_text {
+ if c.header.type == .iTXt {
+ fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text)
+ } else {
+ fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
+ }
+ }
+ defer text_destroy(res)
+ case .bKGD:
+ fmt.printf("[bKGD] %v\n", img.background)
+ case .eXIf:
+ if res, ok_exif := exif(c); ok_exif {
+ /*
+ Other than checking the signature and byte order, we don't handle Exif data.
+ If you wish to interpret it, pass it to an Exif parser.
+ */
+ fmt.printf("[eXIf] %v\n", res)
+ }
+ case .PLTE:
+ if plte, plte_ok := plte(c); plte_ok {
+ fmt.printf("[PLTE] %v\n", plte)
+ } else {
+ fmt.printf("[PLTE] Error\n")
+ }
+ case .hIST:
+ if res, ok_hist := hist(c); ok_hist {
+ fmt.printf("[hIST] %v\n", res)
+ }
+ case .cHRM:
+ if res, ok_chrm := chrm(c); ok_chrm {
+ fmt.printf("[cHRM] %v\n", res)
+ }
+ case .sPLT:
+ res, ok_splt := splt(c)
+ if ok_splt {
+ fmt.printf("[sPLT] %v\n", res)
+ }
+ splt_destroy(res)
+ case .sBIT:
+ if res, ok_sbit := sbit(c); ok_sbit {
+ fmt.printf("[sBIT] %v\n", res)
+ }
+ case .iCCP:
+ res, ok_iccp := iccp(c)
+ if ok_iccp {
+ fmt.printf("[iCCP] %v\n", res)
+ }
+ iccp_destroy(res)
+ case .sRGB:
+ if res, ok_srgb := srgb(c); ok_srgb {
+ fmt.printf("[sRGB] Rendering intent: %v\n", res)
+ }
+ case:
+ type := c.header.type
+ name := chunk_type_to_name(&type)
+ fmt.printf("[%v]: %v\n", name, c.data)
+ }
+ }
+ }
+ }
+
+ fmt.printf("Done parsing metadata.\n")
+
+ if err == nil && .do_not_decompress_image not_in options && .info not_in options {
+ if ok := write_image_as_ppm("out.ppm", img); ok {
+ fmt.println("Saved decoded image.")
+ } else {
+ fmt.println("Error saving out.ppm.")
+ fmt.println(img)
+ }
+ }
+ }
+
+ // Crappy PPM writer used during testing. Don't use in production.
+ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) {
+
+ _bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
+ if v, ok := bg.?; ok {
+ res = v
+ } else {
+ if high {
+ l := u16(30 * 256 + 30)
+
+ if (x & 4 == 0) ~ (y & 4 == 0) {
+ res = [3]u16{l, 0, l}
+ } else {
+ res = [3]u16{l >> 1, 0, l >> 1}
+ }
+ } else {
+ if (x & 4 == 0) ~ (y & 4 == 0) {
+ res = [3]u16{30, 30, 30}
+ } else {
+ res = [3]u16{15, 15, 15}
+ }
+ }
+ }
+ return
+ }
+
+ // profiler.timed_proc();
+ using image
+ using os
+
+ flags: int = O_WRONLY|O_CREATE|O_TRUNC
+
+ img := image
+
+ // PBM 16-bit images are big endian
+ when ODIN_ENDIAN == .Little {
+ if img.depth == 16 {
+ // The pixel components are in Big Endian. Let's byteswap back.
+ input := mem.slice_data_cast([]u16, img.pixels.buf[:])
+ output := mem.slice_data_cast([]u16be, img.pixels.buf[:])
+ #no_bounds_check for v, i in input {
+ output[i] = u16be(v)
+ }
+ }
+ }
+
+ pix := bytes.buffer_to_bytes(&img.pixels)
+
+ if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
+ return false
+ }
+
+ mode: int = 0
+ when ODIN_OS == .Linux || ODIN_OS == .Darwin {
+ // NOTE(justasd): 644 (owner read, write; group read; others read)
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
+ }
+
+ fd, err := open(filename, flags, mode)
+ if err != nil {
+ return false
+ }
+ defer close(fd)
+
+ write_string(fd,
+ fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
+ )
+
+ if channels == 3 {
+ // We don't handle transparency here...
+ write_ptr(fd, raw_data(pix), len(pix))
+ } else {
+ bpp := depth == 16 ? 2 : 1
+ bytes_needed := width * height * 3 * bpp
+
+ op := bytes.Buffer{}
+ bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed)
+ defer bytes.buffer_destroy(&op)
+
+ if channels == 1 {
+ if depth == 16 {
+ assert(len(pix) == width * height * 2)
+ p16 := mem.slice_data_cast([]u16, pix)
+ o16 := mem.slice_data_cast([]u16, op.buf[:])
+ #no_bounds_check for len(p16) != 0 {
+ r := u16(p16[0])
+ o16[0] = r
+ o16[1] = r
+ o16[2] = r
+ p16 = p16[1:]
+ o16 = o16[3:]
+ }
+ } else {
+ o := 0
+ for i := 0; i < len(pix); i += 1 {
+ r := pix[i]
+ op.buf[o ] = r
+ op.buf[o+1] = r
+ op.buf[o+2] = r
+ o += 3
+ }
+ }
+ write_ptr(fd, raw_data(op.buf), len(op.buf))
+ } else if channels == 2 {
+ if depth == 16 {
+ p16 := mem.slice_data_cast([]u16, pix)
+ o16 := mem.slice_data_cast([]u16, op.buf[:])
+
+ bgcol := img.background
+
+ #no_bounds_check for len(p16) != 0 {
+ r := f64(u16(p16[0]))
+ bg: f64
+ if bgcol != nil {
+ v := bgcol.([3]u16)[0]
+ bg = f64(v)
+ }
+ a := f64(u16(p16[1])) / 65535.0
+ l := (a * r) + (1 - a) * bg
+
+ o16[0] = u16(l)
+ o16[1] = u16(l)
+ o16[2] = u16(l)
+
+ p16 = p16[2:]
+ o16 = o16[3:]
+ }
+ } else {
+ o := 0
+ for i := 0; i < len(pix); i += 2 {
+ r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0
+ c := u8(f32(r) * a1)
+ op.buf[o ] = c
+ op.buf[o+1] = c
+ op.buf[o+2] = c
+ o += 3
+ }
+ }
+ write_ptr(fd, raw_data(op.buf), len(op.buf))
+ } else if channels == 4 {
+ if depth == 16 {
+ p16 := mem.slice_data_cast([]u16be, pix)
+ o16 := mem.slice_data_cast([]u16be, op.buf[:])
+
+ #no_bounds_check for len(p16) != 0 {
+
+ bg := _bg(img.background, 0, 0)
+ r := f32(p16[0])
+ g := f32(p16[1])
+ b := f32(p16[2])
+ a := f32(p16[3]) / 65535.0
+
+ lr := (a * r) + (1 - a) * f32(bg[0])
+ lg := (a * g) + (1 - a) * f32(bg[1])
+ lb := (a * b) + (1 - a) * f32(bg[2])
+
+ o16[0] = u16be(lr)
+ o16[1] = u16be(lg)
+ o16[2] = u16be(lb)
+
+ p16 = p16[4:]
+ o16 = o16[3:]
+ }
+ } else {
+ o := 0
+
+ for i := 0; i < len(pix); i += 4 {
+
+ x := (i / 4) % width
+ y := i / width / 4
+
+ _b := _bg(img.background, x, y, false)
+ bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])}
+
+ r := f32(pix[i])
+ g := f32(pix[i+1])
+ b := f32(pix[i+2])
+ a := f32(pix[i+3]) / 255.0
+
+ lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0]))
+ lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1]))
+ lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2]))
+ op.buf[o ] = lr
+ op.buf[o+1] = lg
+ op.buf[o+2] = lb
+ o += 3
+ }
+ }
+ write_ptr(fd, raw_data(op.buf), len(op.buf))
+ } else {
+ return false
+ }
+ }
+ return true
+ }
+*/
+package png
diff --git a/core/image/png/example.odin b/core/image/png/example.odin
deleted file mode 100644
index ce491978b..000000000
--- a/core/image/png/example.odin
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
- Made available under Odin's BSD-3 license.
-
- List of contributors:
- Jeroen van Rijn: Initial implementation.
- Ginger Bill: Cosmetic changes.
-
- An example of how to use `load`.
-*/
-//+build ignore
-package png
-
-import "core:image"
-// import "core:image/png"
-import "core:bytes"
-import "core:fmt"
-
-// For PPM writer
-import "core:mem"
-import "core:os"
-
-main :: proc() {
- track := mem.Tracking_Allocator{}
- mem.tracking_allocator_init(&track, context.allocator)
-
- context.allocator = mem.tracking_allocator(&track)
-
- demo()
-
- if len(track.allocation_map) > 0 {
- fmt.println("Leaks:")
- for _, v in track.allocation_map {
- fmt.printf("\t%v\n\n", v)
- }
- }
-}
-
-demo :: proc() {
- file: string
-
- options := image.Options{.return_metadata}
- err: image.Error
- img: ^image.Image
-
- file = "../../../misc/logo-slim.png"
-
- img, err = load(file, options)
- defer destroy(img)
-
- if err != nil {
- fmt.printf("Trying to read PNG file %v returned %v\n", file, err)
- } else {
- fmt.printf("Image: %vx%vx%v, %v-bit.\n", img.width, img.height, img.channels, img.depth)
-
- if v, ok := img.metadata.(^image.PNG_Info); ok {
- // Handle ancillary chunks as you wish.
- // We provide helper functions for a few types.
- for c in v.chunks {
- #partial switch c.header.type {
- case .tIME:
- if t, t_ok := core_time(c); t_ok {
- fmt.printf("[tIME]: %v\n", t)
- }
- case .gAMA:
- if gama, gama_ok := gamma(c); gama_ok {
- fmt.printf("[gAMA]: %v\n", gama)
- }
- case .pHYs:
- if phys, phys_ok := phys(c); phys_ok {
- if phys.unit == .Meter {
- xm := f32(img.width) / f32(phys.ppu_x)
- ym := f32(img.height) / f32(phys.ppu_y)
- dpi_x, dpi_y := phys_to_dpi(phys)
- fmt.printf("[pHYs] Image resolution is %v x %v pixels per meter.\n", phys.ppu_x, phys.ppu_y)
- fmt.printf("[pHYs] Image resolution is %v x %v DPI.\n", dpi_x, dpi_y)
- fmt.printf("[pHYs] Image dimensions are %v x %v meters.\n", xm, ym)
- } else {
- fmt.printf("[pHYs] x: %v, y: %v pixels per unknown unit.\n", phys.ppu_x, phys.ppu_y)
- }
- }
- case .iTXt, .zTXt, .tEXt:
- res, ok_text := text(c)
- if ok_text {
- if c.header.type == .iTXt {
- fmt.printf("[iTXt] %v (%v:%v): %v\n", res.keyword, res.language, res.keyword_localized, res.text)
- } else {
- fmt.printf("[tEXt/zTXt] %v: %v\n", res.keyword, res.text)
- }
- }
- defer text_destroy(res)
- case .bKGD:
- fmt.printf("[bKGD] %v\n", img.background)
- case .eXIf:
- if res, ok_exif := exif(c); ok_exif {
- /*
- Other than checking the signature and byte order, we don't handle Exif data.
- If you wish to interpret it, pass it to an Exif parser.
- */
- fmt.printf("[eXIf] %v\n", res)
- }
- case .PLTE:
- if plte, plte_ok := plte(c); plte_ok {
- fmt.printf("[PLTE] %v\n", plte)
- } else {
- fmt.printf("[PLTE] Error\n")
- }
- case .hIST:
- if res, ok_hist := hist(c); ok_hist {
- fmt.printf("[hIST] %v\n", res)
- }
- case .cHRM:
- if res, ok_chrm := chrm(c); ok_chrm {
- fmt.printf("[cHRM] %v\n", res)
- }
- case .sPLT:
- res, ok_splt := splt(c)
- if ok_splt {
- fmt.printf("[sPLT] %v\n", res)
- }
- splt_destroy(res)
- case .sBIT:
- if res, ok_sbit := sbit(c); ok_sbit {
- fmt.printf("[sBIT] %v\n", res)
- }
- case .iCCP:
- res, ok_iccp := iccp(c)
- if ok_iccp {
- fmt.printf("[iCCP] %v\n", res)
- }
- iccp_destroy(res)
- case .sRGB:
- if res, ok_srgb := srgb(c); ok_srgb {
- fmt.printf("[sRGB] Rendering intent: %v\n", res)
- }
- case:
- type := c.header.type
- name := chunk_type_to_name(&type)
- fmt.printf("[%v]: %v\n", name, c.data)
- }
- }
- }
- }
-
- fmt.printf("Done parsing metadata.\n")
-
- if err == nil && .do_not_decompress_image not_in options && .info not_in options {
- if ok := write_image_as_ppm("out.ppm", img); ok {
- fmt.println("Saved decoded image.")
- } else {
- fmt.println("Error saving out.ppm.")
- fmt.println(img)
- }
- }
-}
-
-// Crappy PPM writer used during testing. Don't use in production.
-write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: bool) {
-
- _bg :: proc(bg: Maybe([3]u16), x, y: int, high := true) -> (res: [3]u16) {
- if v, ok := bg.?; ok {
- res = v
- } else {
- if high {
- l := u16(30 * 256 + 30)
-
- if (x & 4 == 0) ~ (y & 4 == 0) {
- res = [3]u16{l, 0, l}
- } else {
- res = [3]u16{l >> 1, 0, l >> 1}
- }
- } else {
- if (x & 4 == 0) ~ (y & 4 == 0) {
- res = [3]u16{30, 30, 30}
- } else {
- res = [3]u16{15, 15, 15}
- }
- }
- }
- return
- }
-
- // profiler.timed_proc();
- using image
- using os
-
- flags: int = O_WRONLY|O_CREATE|O_TRUNC
-
- img := image
-
- // PBM 16-bit images are big endian
- when ODIN_ENDIAN == .Little {
- if img.depth == 16 {
- // The pixel components are in Big Endian. Let's byteswap back.
- input := mem.slice_data_cast([]u16, img.pixels.buf[:])
- output := mem.slice_data_cast([]u16be, img.pixels.buf[:])
- #no_bounds_check for v, i in input {
- output[i] = u16be(v)
- }
- }
- }
-
- pix := bytes.buffer_to_bytes(&img.pixels)
-
- if len(pix) == 0 || len(pix) < image.width * image.height * int(image.channels) {
- return false
- }
-
- mode: int = 0
- when ODIN_OS == .Linux || ODIN_OS == .Darwin {
- // NOTE(justasd): 644 (owner read, write; group read; others read)
- mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
- }
-
- fd, err := open(filename, flags, mode)
- if err != nil {
- return false
- }
- defer close(fd)
-
- write_string(fd,
- fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
- )
-
- if channels == 3 {
- // We don't handle transparency here...
- write_ptr(fd, raw_data(pix), len(pix))
- } else {
- bpp := depth == 16 ? 2 : 1
- bytes_needed := width * height * 3 * bpp
-
- op := bytes.Buffer{}
- bytes.buffer_init_allocator(&op, bytes_needed, bytes_needed)
- defer bytes.buffer_destroy(&op)
-
- if channels == 1 {
- if depth == 16 {
- assert(len(pix) == width * height * 2)
- p16 := mem.slice_data_cast([]u16, pix)
- o16 := mem.slice_data_cast([]u16, op.buf[:])
- #no_bounds_check for len(p16) != 0 {
- r := u16(p16[0])
- o16[0] = r
- o16[1] = r
- o16[2] = r
- p16 = p16[1:]
- o16 = o16[3:]
- }
- } else {
- o := 0
- for i := 0; i < len(pix); i += 1 {
- r := pix[i]
- op.buf[o ] = r
- op.buf[o+1] = r
- op.buf[o+2] = r
- o += 3
- }
- }
- write_ptr(fd, raw_data(op.buf), len(op.buf))
- } else if channels == 2 {
- if depth == 16 {
- p16 := mem.slice_data_cast([]u16, pix)
- o16 := mem.slice_data_cast([]u16, op.buf[:])
-
- bgcol := img.background
-
- #no_bounds_check for len(p16) != 0 {
- r := f64(u16(p16[0]))
- bg: f64
- if bgcol != nil {
- v := bgcol.([3]u16)[0]
- bg = f64(v)
- }
- a := f64(u16(p16[1])) / 65535.0
- l := (a * r) + (1 - a) * bg
-
- o16[0] = u16(l)
- o16[1] = u16(l)
- o16[2] = u16(l)
-
- p16 = p16[2:]
- o16 = o16[3:]
- }
- } else {
- o := 0
- for i := 0; i < len(pix); i += 2 {
- r := pix[i]; a := pix[i+1]; a1 := f32(a) / 255.0
- c := u8(f32(r) * a1)
- op.buf[o ] = c
- op.buf[o+1] = c
- op.buf[o+2] = c
- o += 3
- }
- }
- write_ptr(fd, raw_data(op.buf), len(op.buf))
- } else if channels == 4 {
- if depth == 16 {
- p16 := mem.slice_data_cast([]u16be, pix)
- o16 := mem.slice_data_cast([]u16be, op.buf[:])
-
- #no_bounds_check for len(p16) != 0 {
-
- bg := _bg(img.background, 0, 0)
- r := f32(p16[0])
- g := f32(p16[1])
- b := f32(p16[2])
- a := f32(p16[3]) / 65535.0
-
- lr := (a * r) + (1 - a) * f32(bg[0])
- lg := (a * g) + (1 - a) * f32(bg[1])
- lb := (a * b) + (1 - a) * f32(bg[2])
-
- o16[0] = u16be(lr)
- o16[1] = u16be(lg)
- o16[2] = u16be(lb)
-
- p16 = p16[4:]
- o16 = o16[3:]
- }
- } else {
- o := 0
-
- for i := 0; i < len(pix); i += 4 {
-
- x := (i / 4) % width
- y := i / width / 4
-
- _b := _bg(img.background, x, y, false)
- bgcol := [3]u8{u8(_b[0]), u8(_b[1]), u8(_b[2])}
-
- r := f32(pix[i])
- g := f32(pix[i+1])
- b := f32(pix[i+2])
- a := f32(pix[i+3]) / 255.0
-
- lr := u8(f32(r) * a + (1 - a) * f32(bgcol[0]))
- lg := u8(f32(g) * a + (1 - a) * f32(bgcol[1]))
- lb := u8(f32(b) * a + (1 - a) * f32(bgcol[2]))
- op.buf[o ] = lr
- op.buf[o+1] = lg
- op.buf[o+2] = lb
- o += 3
- }
- }
- write_ptr(fd, raw_data(op.buf), len(op.buf))
- } else {
- return false
- }
- }
- return true
-}
diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin
index 7b6367694..f094b54a9 100644
--- a/core/image/png/helpers.odin
+++ b/core/image/png/helpers.odin
@@ -8,6 +8,7 @@
These are a few useful utility functions to work with PNG images.
*/
+
package png
import "core:image"
diff --git a/core/image/png/png.odin b/core/image/png/png.odin
index 177269722..2d3665e94 100644
--- a/core/image/png/png.odin
+++ b/core/image/png/png.odin
@@ -8,10 +8,7 @@
*/
-// package png implements a PNG image reader
-//
-// The PNG specification is at https://www.w3.org/TR/PNG/.
-//+vet !using-stmt
+#+vet !using-stmt
package png
import "core:compress"
@@ -1619,4 +1616,4 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
@(init, private)
_register :: proc() {
image.register(.PNG, load_from_bytes, destroy)
-} \ No newline at end of file
+}
diff --git a/core/image/png/png_js.odin b/core/image/png/png_js.odin
index 57c27fc64..dd9e74526 100644
--- a/core/image/png/png_js.odin
+++ b/core/image/png/png_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package png
load :: proc{load_from_bytes, load_from_context}
diff --git a/core/image/png/png_os.odin b/core/image/png/png_os.odin
index cc65e7b42..8e0706206 100644
--- a/core/image/png/png_os.odin
+++ b/core/image/png/png_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package png
import "core:os"
diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin
index 5cf252fcc..6b6149e60 100644
--- a/core/image/qoi/qoi.odin
+++ b/core/image/qoi/qoi.odin
@@ -9,7 +9,7 @@
// package qoi implements a QOI image reader
//
-// The QOI specification is at https://qoiformat.org.
+// The QOI specification is at [[ https://qoiformat.org ]].
package qoi
import "core:image"
diff --git a/core/image/qoi/qoi_js.odin b/core/image/qoi/qoi_js.odin
index 2c23cc17a..4a69e98a0 100644
--- a/core/image/qoi/qoi_js.odin
+++ b/core/image/qoi/qoi_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package qoi
save :: proc{save_to_buffer}
diff --git a/core/image/qoi/qoi_os.odin b/core/image/qoi/qoi_os.odin
index efcec6c52..c85fdd839 100644
--- a/core/image/qoi/qoi_os.odin
+++ b/core/image/qoi/qoi_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package qoi
import "core:os"
diff --git a/core/image/tga/tga_js.odin b/core/image/tga/tga_js.odin
index d98b241a7..9261be8c6 100644
--- a/core/image/tga/tga_js.odin
+++ b/core/image/tga/tga_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package tga
save :: proc{save_to_buffer}
diff --git a/core/image/tga/tga_os.odin b/core/image/tga/tga_os.odin
index 12747a684..a78998105 100644
--- a/core/image/tga/tga_os.odin
+++ b/core/image/tga/tga_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package tga
import "core:os"
diff --git a/core/io/util.odin b/core/io/util.odin
index c24eb99c5..e65a69fb3 100644
--- a/core/io/util.odin
+++ b/core/io/util.odin
@@ -340,6 +340,9 @@ _limited_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte,
l := (^Limited_Reader)(stream_data)
#partial switch mode {
case .Read:
+ if len(p) == 0 {
+ return 0, nil
+ }
if l.n <= 0 {
return 0, .EOF
}
@@ -376,11 +379,12 @@ Section_Reader :: struct {
limit: i64,
}
-section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) {
+section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) -> Reader {
s.r = r
+ s.base = off
s.off = off
s.limit = off + n
- return
+ return section_reader_to_stream(s)
}
section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) {
out.data = s
@@ -393,6 +397,9 @@ _section_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte,
s := (^Section_Reader)(stream_data)
#partial switch mode {
case .Read:
+ if len(p) == 0 {
+ return 0, nil
+ }
if s.off >= s.limit {
return 0, .EOF
}
@@ -404,6 +411,9 @@ _section_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte,
s.off += i64(n)
return
case .Read_At:
+ if len(p) == 0 {
+ return 0, nil
+ }
p, off := p, offset
if off < 0 || off >= s.limit - s.base {
diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin
index f05f7a258..e45f99523 100644
--- a/core/log/file_console_logger.odin
+++ b/core/log/file_console_logger.odin
@@ -1,5 +1,5 @@
-//+build !freestanding
-//+build !orca
+#+build !freestanding
+#+build !orca
package log
import "core:encoding/ansi"
diff --git a/core/math/big/common.odin b/core/math/big/common.odin
index fabf39520..5428b00ee 100644
--- a/core/math/big/common.odin
+++ b/core/math/big/common.odin
@@ -195,7 +195,7 @@ Error_String :: #sparse[Error]string{
}
Primality_Flag :: enum u8 {
- Blum_Blum_Shub = 0, // Make prime congruent to 3 mod 4
+ Blum_Blum_Shub = 0, // Make prime congruent to 3 mod 4
Safe = 1, // Make sure (p-1)/2 is prime as well (implies .Blum_Blum_Shub)
Second_MSB_On = 3, // Make the 2nd highest bit one
}
diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin
index 5938dafde..eab36b951 100644
--- a/core/math/big/tune.odin
+++ b/core/math/big/tune.odin
@@ -7,7 +7,7 @@
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
*/
-//+build ignore
+#+build ignore
package math_big
import "core:time"
diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin
index 363a95887..5444f89e2 100644
--- a/core/math/linalg/glsl/linalg_glsl.odin
+++ b/core/math/linalg/glsl/linalg_glsl.odin
@@ -22,9 +22,9 @@ F32_EPSILON :: 1e-7
F64_EPSILON :: 1e-15
// Odin matrices are stored internally as Column-Major, which matches OpenGL/GLSL by default
-mat2 :: distinct matrix[2, 2]f32
-mat3 :: distinct matrix[3, 3]f32
-mat4 :: distinct matrix[4, 4]f32
+mat2 :: matrix[2, 2]f32
+mat3 :: matrix[3, 3]f32
+mat4 :: matrix[4, 4]f32
mat2x2 :: mat2
mat3x3 :: mat3
mat4x4 :: mat4
@@ -33,52 +33,52 @@ mat4x4 :: mat4
// but they match how GLSL and OpenGL defines them in name
// Odin: matrix[R, C]f32
// GLSL: matCxR
-mat3x2 :: distinct matrix[2, 3]f32
-mat4x2 :: distinct matrix[2, 4]f32
-mat2x3 :: distinct matrix[3, 2]f32
-mat4x3 :: distinct matrix[3, 4]f32
-mat2x4 :: distinct matrix[4, 2]f32
-mat3x4 :: distinct matrix[4, 3]f32
+mat3x2 :: matrix[2, 3]f32
+mat4x2 :: matrix[2, 4]f32
+mat2x3 :: matrix[3, 2]f32
+mat4x3 :: matrix[3, 4]f32
+mat2x4 :: matrix[4, 2]f32
+mat3x4 :: matrix[4, 3]f32
-vec2 :: distinct [2]f32
-vec3 :: distinct [3]f32
-vec4 :: distinct [4]f32
+vec2 :: [2]f32
+vec3 :: [3]f32
+vec4 :: [4]f32
-ivec2 :: distinct [2]i32
-ivec3 :: distinct [3]i32
-ivec4 :: distinct [4]i32
+ivec2 :: [2]i32
+ivec3 :: [3]i32
+ivec4 :: [4]i32
-uvec2 :: distinct [2]u32
-uvec3 :: distinct [3]u32
-uvec4 :: distinct [4]u32
+uvec2 :: [2]u32
+uvec3 :: [3]u32
+uvec4 :: [4]u32
-bvec2 :: distinct [2]bool
-bvec3 :: distinct [3]bool
-bvec4 :: distinct [4]bool
+bvec2 :: [2]bool
+bvec3 :: [3]bool
+bvec4 :: [4]bool
-quat :: distinct quaternion128
+quat :: quaternion128
// Double Precision (f64) Floating Point Types
-dmat2 :: distinct matrix[2, 2]f64
-dmat3 :: distinct matrix[3, 3]f64
-dmat4 :: distinct matrix[4, 4]f64
+dmat2 :: matrix[2, 2]f64
+dmat3 :: matrix[3, 3]f64
+dmat4 :: matrix[4, 4]f64
dmat2x2 :: dmat2
dmat3x3 :: dmat3
dmat4x4 :: dmat4
-dmat3x2 :: distinct matrix[2, 3]f64
-dmat4x2 :: distinct matrix[2, 4]f64
-dmat2x3 :: distinct matrix[3, 2]f64
-dmat4x3 :: distinct matrix[3, 4]f64
-dmat2x4 :: distinct matrix[4, 2]f64
-dmat3x4 :: distinct matrix[4, 3]f64
+dmat3x2 :: matrix[2, 3]f64
+dmat4x2 :: matrix[2, 4]f64
+dmat2x3 :: matrix[3, 2]f64
+dmat4x3 :: matrix[3, 4]f64
+dmat2x4 :: matrix[4, 2]f64
+dmat3x4 :: matrix[4, 3]f64
-dvec2 :: distinct [2]f64
-dvec3 :: distinct [3]f64
-dvec4 :: distinct [4]f64
+dvec2 :: [2]f64
+dvec3 :: [3]f64
+dvec4 :: [4]f64
-dquat :: distinct quaternion256
+dquat :: quaternion256
cos :: proc{
cos_f32,
diff --git a/core/math/linalg/hlsl/linalg_hlsl.odin b/core/math/linalg/hlsl/linalg_hlsl.odin
index f5e8bf147..a89fdddd3 100644
--- a/core/math/linalg/hlsl/linalg_hlsl.odin
+++ b/core/math/linalg/hlsl/linalg_hlsl.odin
@@ -21,89 +21,89 @@ LN10 :: 2.30258509299404568401799145468436421
FLOAT_EPSILON :: 1e-7
DOUBLE_EPSILON :: 1e-15
-// Aliases (not distinct) of types
+// Aliases (not distict) of types
float :: f32
double :: f64
int :: builtin.i32
uint :: builtin.u32
// Odin matrices are stored internally as Column-Major, which matches the internal layout of HLSL by default
-float1x1 :: distinct matrix[1, 1]float
-float2x2 :: distinct matrix[2, 2]float
-float3x3 :: distinct matrix[3, 3]float
-float4x4 :: distinct matrix[4, 4]float
-
-float1x2 :: distinct matrix[1, 2]float
-float1x3 :: distinct matrix[1, 3]float
-float1x4 :: distinct matrix[1, 4]float
-float2x1 :: distinct matrix[2, 1]float
-float2x3 :: distinct matrix[2, 3]float
-float2x4 :: distinct matrix[2, 4]float
-float3x1 :: distinct matrix[3, 1]float
-float3x2 :: distinct matrix[3, 2]float
-float3x4 :: distinct matrix[3, 4]float
-float4x1 :: distinct matrix[4, 1]float
-float4x2 :: distinct matrix[4, 2]float
-float4x3 :: distinct matrix[4, 3]float
-
-float2 :: distinct [2]float
-float3 :: distinct [3]float
-float4 :: distinct [4]float
-
-int2 :: distinct [2]int
-int3 :: distinct [3]int
-int4 :: distinct [4]int
-
-uint2 :: distinct [2]uint
-uint3 :: distinct [3]uint
-uint4 :: distinct [4]uint
-
-bool2 :: distinct [2]bool
-bool3 :: distinct [3]bool
-bool4 :: distinct [4]bool
+float1x1 :: matrix[1, 1]float
+float2x2 :: matrix[2, 2]float
+float3x3 :: matrix[3, 3]float
+float4x4 :: matrix[4, 4]float
+
+float1x2 :: matrix[1, 2]float
+float1x3 :: matrix[1, 3]float
+float1x4 :: matrix[1, 4]float
+float2x1 :: matrix[2, 1]float
+float2x3 :: matrix[2, 3]float
+float2x4 :: matrix[2, 4]float
+float3x1 :: matrix[3, 1]float
+float3x2 :: matrix[3, 2]float
+float3x4 :: matrix[3, 4]float
+float4x1 :: matrix[4, 1]float
+float4x2 :: matrix[4, 2]float
+float4x3 :: matrix[4, 3]float
+
+float2 :: [2]float
+float3 :: [3]float
+float4 :: [4]float
+
+int2 :: [2]int
+int3 :: [3]int
+int4 :: [4]int
+
+uint2 :: [2]uint
+uint3 :: [3]uint
+uint4 :: [4]uint
+
+bool2 :: [2]bool
+bool3 :: [3]bool
+bool4 :: [4]bool
// Double Precision (double) Floating Point Types
-double1x1 :: distinct matrix[1, 1]double
-double2x2 :: distinct matrix[2, 2]double
-double3x3 :: distinct matrix[3, 3]double
-double4x4 :: distinct matrix[4, 4]double
-
-double1x2 :: distinct matrix[1, 2]double
-double1x3 :: distinct matrix[1, 3]double
-double1x4 :: distinct matrix[1, 4]double
-double2x1 :: distinct matrix[2, 1]double
-double2x3 :: distinct matrix[2, 3]double
-double2x4 :: distinct matrix[2, 4]double
-double3x1 :: distinct matrix[3, 1]double
-double3x2 :: distinct matrix[3, 2]double
-double3x4 :: distinct matrix[3, 4]double
-double4x1 :: distinct matrix[4, 1]double
-double4x2 :: distinct matrix[4, 2]double
-double4x3 :: distinct matrix[4, 3]double
-
-double2 :: distinct [2]double
-double3 :: distinct [3]double
-double4 :: distinct [4]double
-
-
-int1x1 :: distinct matrix[1, 1]int
-int2x2 :: distinct matrix[2, 2]int
-int3x3 :: distinct matrix[3, 3]int
-int4x4 :: distinct matrix[4, 4]int
-
-int1x2 :: distinct matrix[1, 2]int
-int1x3 :: distinct matrix[1, 3]int
-int1x4 :: distinct matrix[1, 4]int
-int2x1 :: distinct matrix[2, 1]int
-int2x3 :: distinct matrix[2, 3]int
-int2x4 :: distinct matrix[2, 4]int
-int3x1 :: distinct matrix[3, 1]int
-int3x2 :: distinct matrix[3, 2]int
-int3x4 :: distinct matrix[3, 4]int
-int4x1 :: distinct matrix[4, 1]int
-int4x2 :: distinct matrix[4, 2]int
-int4x3 :: distinct matrix[4, 3]int
+double1x1 :: matrix[1, 1]double
+double2x2 :: matrix[2, 2]double
+double3x3 :: matrix[3, 3]double
+double4x4 :: matrix[4, 4]double
+
+double1x2 :: matrix[1, 2]double
+double1x3 :: matrix[1, 3]double
+double1x4 :: matrix[1, 4]double
+double2x1 :: matrix[2, 1]double
+double2x3 :: matrix[2, 3]double
+double2x4 :: matrix[2, 4]double
+double3x1 :: matrix[3, 1]double
+double3x2 :: matrix[3, 2]double
+double3x4 :: matrix[3, 4]double
+double4x1 :: matrix[4, 1]double
+double4x2 :: matrix[4, 2]double
+double4x3 :: matrix[4, 3]double
+
+double2 :: [2]double
+double3 :: [3]double
+double4 :: [4]double
+
+
+int1x1 :: matrix[1, 1]int
+int2x2 :: matrix[2, 2]int
+int3x3 :: matrix[3, 3]int
+int4x4 :: matrix[4, 4]int
+
+int1x2 :: matrix[1, 2]int
+int1x3 :: matrix[1, 3]int
+int1x4 :: matrix[1, 4]int
+int2x1 :: matrix[2, 1]int
+int2x3 :: matrix[2, 3]int
+int2x4 :: matrix[2, 4]int
+int3x1 :: matrix[3, 1]int
+int3x2 :: matrix[3, 2]int
+int3x4 :: matrix[3, 4]int
+int4x1 :: matrix[4, 1]int
+int4x2 :: matrix[4, 2]int
+int4x3 :: matrix[4, 3]int
cos :: proc{
cos_float,
diff --git a/core/math/math.odin b/core/math/math.odin
index 957e1672b..0e21afa67 100644
--- a/core/math/math.odin
+++ b/core/math/math.odin
@@ -406,6 +406,12 @@ remap :: proc "contextless" (old_value, old_min, old_max, new_min, new_max: $T)
}
@(require_results)
+remap_clamped :: proc "contextless" (old_value, old_min, old_max, new_min, new_max: $T) -> (x: T) where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) {
+ remapped := #force_inline remap(old_value, old_min, old_max, new_min, new_max)
+ return clamp(remapped, new_min, new_max)
+}
+
+@(require_results)
wrap :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) {
tmp := mod(x, y)
return y + tmp if tmp < 0 else tmp
@@ -438,11 +444,11 @@ bias :: proc "contextless" (t, b: $T) -> T where intrinsics.type_is_numeric(T) {
return t / (((1/b) - 2) * (1 - t) + 1)
}
@(require_results)
-gain :: proc "contextless" (t, g: $T) -> T where intrinsics.type_is_numeric(T) {
+gain :: proc "contextless" (t, g: $T) -> T where intrinsics.type_is_float(T) {
if t < 0.5 {
- return bias(t*2, g)*0.5
+ return bias(t*2, g) * 0.5
}
- return bias(t*2 - 1, 1 - g)*0.5 + 0.5
+ return bias(t*2 - 1, 1 - g) * 0.5 + 0.5
}
diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin
index 041efd272..2584df71f 100644
--- a/core/math/math_basic.odin
+++ b/core/math/math_basic.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package math
import "base:intrinsics"
diff --git a/core/math/math_basic_js.odin b/core/math/math_basic_js.odin
index 5b9adabcd..2604ebc8b 100644
--- a/core/math/math_basic_js.odin
+++ b/core/math/math_basic_js.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package math
import "base:intrinsics"
diff --git a/core/math/noise/internal.odin b/core/math/noise/internal.odin
index bd97bd45c..f75c0ee87 100644
--- a/core/math/noise/internal.odin
+++ b/core/math/noise/internal.odin
@@ -4,7 +4,7 @@
Ported from https://github.com/KdotJPG/OpenSimplex2.
Copyright 2022 Yuki2 (https://github.com/NoahR02)
*/
-//+private
+#+private
package math_noise
/*
diff --git a/core/math/noise/opensimplex2.odin b/core/math/noise/opensimplex2.odin
index d28356f2c..634c32948 100644
--- a/core/math/noise/opensimplex2.odin
+++ b/core/math/noise/opensimplex2.odin
@@ -1,8 +1,8 @@
/*
OpenSimplex2 noise implementation.
- Ported from https://github.com/KdotJPG/OpenSimplex2.
- Copyright 2022 Yuki2 (https://github.com/NoahR02)
+ Ported from [[ https://github.com/KdotJPG/OpenSimplex2 }].
+ Copyright 2022 Yuki2 [[ https://github.com/NoahR02 ]]
*/
package math_noise
@@ -177,4 +177,4 @@ noise_4d_fallback :: proc(seed: i64, coord: Vec4) -> (value: f32) {
// Get points for A4 lattice
skew := f64(SKEW_4D) * (coord.x + coord.y + coord.z + coord.w)
return _internal_noise_4d_unskewed_base(seed, coord + skew)
-} \ No newline at end of file
+}
diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin
index acd77241f..fac58daaf 100644
--- a/core/mem/alloc.odin
+++ b/core/mem/alloc.odin
@@ -2,109 +2,711 @@ package mem
import "base:runtime"
-// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
-Allocator_Mode :: runtime.Allocator_Mode
+//NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
+
/*
-Allocator_Mode :: enum byte {
- Alloc,
- Free,
- Free_All,
- Resize,
- Query_Features,
- Alloc_Non_Zeroed,
- Resize_Non_Zeroed,
-}
+A request to allocator procedure.
+
+This type represents a type of allocation request made to an allocator
+procedure. There is one allocator procedure per allocator, and this value is
+used to discriminate between different functions of the allocator.
+
+The type is defined as follows:
+
+ Allocator_Mode :: enum byte {
+ Alloc,
+ Alloc_Non_Zeroed,
+ Free,
+ Free_All,
+ Resize,
+ Resize_Non_Zeroed,
+ Query_Features,
+ }
+
+Depending on which value is used, the allocator procedure will perform different
+functions:
+
+- `Alloc`: Allocates a memory region with a given `size` and `alignment`.
+- `Alloc_Non_Zeroed`: Same as `Alloc` without explicit zero-initialization of
+ the memory region.
+- `Free`: Free a memory region located at address `ptr` with a given `size`.
+- `Free_All`: Free all memory allocated using this allocator.
+- `Resize`: Resize a memory region located at address `old_ptr` with size
+ `old_size` to be `size` bytes in length and have the specified `alignment`,
+ in case a re-alllocation occurs.
+- `Resize_Non_Zeroed`: Same as `Resize`, without explicit zero-initialization.
*/
+Allocator_Mode :: runtime.Allocator_Mode
-Allocator_Mode_Set :: runtime.Allocator_Mode_Set
/*
-Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
+A set of allocator features.
+
+This type represents values that contain a set of features an allocator has.
+Currently the type is defined as follows:
+
+ Allocator_Mode_Set :: distinct bit_set[Allocator_Mode];
*/
+Allocator_Mode_Set :: runtime.Allocator_Mode_Set
-Allocator_Query_Info :: runtime.Allocator_Query_Info
/*
-Allocator_Query_Info :: struct {
- pointer: rawptr,
- size: Maybe(int),
- alignment: Maybe(int),
-}
+Allocator information.
+
+This type represents information about a given allocator at a specific point
+in time. Currently the type is defined as follows:
+
+ Allocator_Query_Info :: struct {
+ pointer: rawptr,
+ size: Maybe(int),
+ alignment: Maybe(int),
+ }
+
+- `pointer`: Pointer to a backing buffer.
+- `size`: Size of the backing buffer.
+- `alignment`: The allocator's alignment.
+
+If not applicable, any of these fields may be `nil`.
*/
+Allocator_Query_Info :: runtime.Allocator_Query_Info
+
+/*
+An allocation request error.
+This type represents error values the allocators may return upon requests.
+
+ Allocator_Error :: enum byte {
+ None = 0,
+ Out_Of_Memory = 1,
+ Invalid_Pointer = 2,
+ Invalid_Argument = 3,
+ Mode_Not_Implemented = 4,
+ }
+
+The meaning of the errors is as follows:
+
+- `None`: No error.
+- `Out_Of_Memory`: Either:
+ 1. The allocator has ran out of the backing buffer, or the requested
+ allocation size is too large to fit into a backing buffer.
+ 2. The operating system error during memory allocation.
+ 3. The backing allocator was used to allocate a new backing buffer and the
+ backing allocator returned Out_Of_Memory.
+- `Invalid_Pointer`: The pointer referring to a memory region does not belong
+ to any of the allocators backing buffers or does not point to a valid start
+ of an allocation made in that allocator.
+- `Invalid_Argument`: Can occur if one of the arguments makes it impossible to
+ satisfy a request (i.e. having alignment larger than the backing buffer
+ of the allocation).
+- `Mode_Not_Implemented`: The allocator does not support the specified
+ operation. For example, an arena does not support freeing individual
+ allocations.
+*/
Allocator_Error :: runtime.Allocator_Error
+
/*
-Allocator_Error :: enum byte {
- None = 0,
- Out_Of_Memory = 1,
- Invalid_Pointer = 2,
- Invalid_Argument = 3,
- Mode_Not_Implemented = 4,
-}
+The allocator procedure.
+
+This type represents allocation procedures. An allocation procedure is a single
+procedure, implementing all allocator functions such as allocating the memory,
+freeing the memory, etc.
+
+Currently the type is defined as follows:
+
+ Allocator_Proc :: #type proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size: int,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ location: Source_Code_Location = #caller_location,
+ ) -> ([]byte, Allocator_Error);
+
+The function of this procedure and the meaning of parameters depends on the
+value of the `mode` parameter. For any operation the following constraints
+apply:
+
+- The `alignment` must be a power of two.
+- The `size` must be a positive integer.
+
+## 1. `.Alloc`, `.Alloc_Non_Zeroed`
+
+Allocates a memory region of size `size`, aligned on a boundary specified by
+`alignment`.
+
+**Inputs**:
+- `allocator_data`: Pointer to the allocator data.
+- `mode`: `.Alloc` or `.Alloc_Non_Zeroed`.
+- `size`: The desired size of the memory region.
+- `alignment`: The desired alignmnet of the allocation.
+- `old_memory`: Unused, should be `nil`.
+- `old_size`: Unused, should be 0.
+
+**Returns**:
+1. The memory region, if allocated successfully, or `nil` otherwise.
+2. An error, if allocation failed.
+
+**Note**: The nil allocator may return `nil`, even if no error is returned.
+Always check both the error and the allocated buffer.
+
+**Note**: The `.Alloc` mode is required to be implemented for an allocator
+and can not return a `.Mode_Not_Implemented` error.
+
+## 2. `Free`
+
+Frees a memory region located at the address specified by `old_memory`. If the
+allocator does not track sizes of allocations, the size should be specified in
+the `old_size` parameter.
+
+**Inputs**:
+- `allocator_data`: Pointer to the allocator data.
+- `mode`: `.Free`.
+- `size`: Unused, should be 0.
+- `alignment`: Unused, should be 0.
+- `old_memory`: Pointer to the memory region to free.
+- `old_size`: The size of the memory region to free. This parameter is optional
+ if the allocator keeps track of the sizes of allocations.
+
+**Returns**:
+1. `nil`
+2. Error, if freeing failed.
+
+## 3. `Free_All`
+
+Frees all allocations, associated with the allocator, making it available for
+further allocations using the same backing buffers.
+
+**Inputs**:
+- `allocator_data`: Pointer to the allocator data.
+- `mode`: `.Free_All`.
+- `size`: Unused, should be 0.
+- `alignment`: Unused, should be 0.
+- `old_memory`: Unused, should be `nil`.
+- `old_size`: Unused, should be `0`.
+
+**Returns**:
+1. `nil`.
+2. Error, if freeing failed.
+
+## 4. `Resize`, `Resize_Non_Zeroed`
+
+Resizes the memory region, of the size `old_size` located at the address
+specified by `old_memory` to have the new size `size`. The slice of the new
+memory region is returned from the procedure. The allocator may attempt to
+keep the new memory region at the same address as the previous allocation,
+however no such guarantee is made. Do not assume the new memory region will
+be at the same address as the old memory region.
+
+If `old_memory` pointer is `nil`, this function acts just like `.Alloc` or
+`.Alloc_Non_Zeroed`, using `size` and `alignment` to allocate a new memory
+region.
+
+If `new_size` is `nil`, the procedure acts just like `.Free`, freeing the
+memory region `old_size` bytes in length, located at the address specified by
+`old_memory`.
+
+If the `old_memory` pointer is not aligned to the boundary specified by
+`alignment`, the procedure relocates the buffer such that the reallocated
+buffer is aligned to the boundary specified by `alignment`.
+
+**Inputs**:
+- `allocator_data`: Pointer to the allocator data.
+- `mode`: `.Resize` or `.Resize_All`.
+- `size`: The desired new size of the memory region.
+- `alignment`: The alignment of the new memory region, if its allocated
+- `old_memory`: The pointer to the memory region to resize.
+- `old_size`: The size of the memory region to resize. If the allocator
+ keeps track of the sizes of allocations, this parameter is optional.
+
+**Returns**:
+1. The slice of the memory region after resize operation, if successfull,
+ `nil` otherwise.
+2. An error, if the resize failed.
+
+**Note**: Some allocators may return `nil`, even if no error is returned.
+Always check both the error and the allocated buffer.
+
+**Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
+no-op, and should not return errors.
*/
Allocator_Proc :: runtime.Allocator_Proc
+
/*
-Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, location: Source_Code_Location = #caller_location) -> ([]byte, Allocator_Error);
-*/
+Allocator.
+
+This type represents generic interface for all allocators. Currently this type
+is defined as follows:
+ Allocator :: struct {
+ procedure: Allocator_Proc,
+ data: rawptr,
+ }
+
+- `procedure`: Pointer to the allocation procedure.
+- `data`: Pointer to the allocator data.
+*/
Allocator :: runtime.Allocator
+
/*
-Allocator :: struct {
- procedure: Allocator_Proc,
- data: rawptr,
-}
-*/
+Default alignment.
+This value is the default alignment for all platforms that is used, if the
+alignment is not specified explicitly.
+*/
DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
+/*
+Default page size.
+
+This value is the default page size for the current platform.
+*/
DEFAULT_PAGE_SIZE ::
64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else
16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
4 * 1024
+/*
+Allocate memory.
+
+This function allocates `size` bytes of memory, aligned to a boundary specified
+by `alignment` using the allocator specified by `allocator`.
+
+If the `size` parameter is `0`, the operation is a no-op.
+
+**Inputs**:
+- `size`: The desired size of the allocated memory region.
+- `alignment`: The desired alignment of the allocated memory region.
+- `allocator`: The allocator to allocate from.
+
+**Returns**:
+1. Pointer to the allocated memory, or `nil` if allocation failed.
+2. Error, if the allocation failed.
+
+**Errors**:
+- `None`: If no error occurred.
+- `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
+ backing buffers, the backing allocator has ran out of space, or an operating
+ system failure occurred.
+- `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
+ power of two.
+*/
@(require_results)
-alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
+alloc :: proc(
+ size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
data, err := runtime.mem_alloc(size, alignment, allocator, loc)
return raw_data(data), err
}
+/*
+Allocate memory.
+
+This function allocates `size` bytes of memory, aligned to a boundary specified
+by `alignment` using the allocator specified by `allocator`.
+
+**Inputs**:
+- `size`: The desired size of the allocated memory region.
+- `alignment`: The desired alignment of the allocated memory region.
+- `allocator`: The allocator to allocate from.
+
+**Returns**:
+1. Slice of the allocated memory region, or `nil` if allocation failed.
+2. Error, if the allocation failed.
+
+**Errors**:
+- `None`: If no error occurred.
+- `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
+ backing buffers, the backing allocator has ran out of space, or an operating
+ system failure occurred.
+- `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
+ power of two.
+*/
@(require_results)
-alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+alloc_bytes :: proc(
+ size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
return runtime.mem_alloc(size, alignment, allocator, loc)
}
+/*
+Allocate non-zeroed memory.
+
+This function allocates `size` bytes of memory, aligned to a boundary specified
+by `alignment` using the allocator specified by `allocator`. This procedure
+does not explicitly zero-initialize allocated memory region.
+
+**Inputs**:
+- `size`: The desired size of the allocated memory region.
+- `alignment`: The desired alignment of the allocated memory region.
+- `allocator`: The allocator to allocate from.
+
+**Returns**:
+1. Slice of the allocated memory region, or `nil` if allocation failed.
+2. Error, if the allocation failed.
+
+**Errors**:
+- `None`: If no error occurred.
+- `Out_Of_Memory`: Occurs when the allocator runs out of space in any of its
+ backing buffers, the backing allocator has ran out of space, or an operating
+ system failure occurred.
+- `Invalid_Argument`: If the supplied `size` is negative, alignment is not a
+ power of two.
+*/
@(require_results)
-alloc_bytes_non_zeroed :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+alloc_bytes_non_zeroed :: proc(
+ size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
return runtime.mem_alloc_non_zeroed(size, alignment, allocator, loc)
}
-free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
+/*
+Free memory.
+
+This procedure frees memory region located at the address, specified by `ptr`,
+allocated from the allocator specified by `allocator`.
+
+**Inputs**:
+- `ptr`: Pointer to the memory region to free.
+- `allocator`: The allocator to free to.
+
+**Returns**:
+- The error, if freeing failed.
+
+**Errors**:
+- `None`: When no error has occurred.
+- `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
+ or does not point to a valid allocation.
+- `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
+mode.
+*/
+free :: proc(
+ ptr: rawptr,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.mem_free(ptr, allocator, loc)
}
-free_with_size :: proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
- return runtime.mem_free_with_size(ptr, byte_count, allocator, loc)
+/*
+Free a memory region.
+
+This procedure frees `size` bytes of memory region located at the address,
+specified by `ptr`, allocated from the allocator specified by `allocator`.
+
+If the `size` parameter is `0`, this call is equivalent to `free()`.
+
+**Inputs**:
+- `ptr`: Pointer to the memory region to free.
+- `size`: The size of the memory region to free.
+- `allocator`: The allocator to free to.
+
+**Returns**:
+- The error, if freeing failed.
+
+**Errors**:
+- `None`: When no error has occurred.
+- `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
+ or does not point to a valid allocation.
+- `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
+mode.
+*/
+free_with_size :: proc(
+ ptr: rawptr,
+ size: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
+ return runtime.mem_free_with_size(ptr, size, allocator, loc)
}
-free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
+/*
+Free a memory region.
+
+This procedure frees memory region, specified by `bytes`, allocated from the
+allocator specified by `allocator`.
+
+If the length of the specified slice is zero, the `.Invalid_Argument` error
+is returned.
+
+**Inputs**:
+- `bytes`: The memory region to free.
+- `allocator`: The allocator to free to.
+
+**Returns**:
+- The error, if freeing failed.
+
+**Errors**:
+- `None`: When no error has occurred.
+- `Invalid_Pointer`: The specified pointer is not owned by the specified allocator,
+ or does not point to a valid allocation.
+- `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
+mode.
+*/
+free_bytes :: proc(
+ bytes: []byte,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.mem_free_bytes(bytes, allocator, loc)
}
+/*
+Free all allocations.
+
+This procedure frees all allocations made on the allocator specified by
+`allocator` to that allocator, making it available for further allocations.
+
+**Inputs**:
+- `allocator`: The allocator to free to.
+
+**Errors**:
+- `None`: When no error has occurred.
+- `Mode_Not_Implemented`: If the specified allocator does not support the `.Free`
+mode.
+*/
free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return runtime.mem_free_all(allocator, loc)
}
+/*
+Resize a memory region.
+
+This procedure resizes a memory region, `old_size` bytes in size, located at
+the address specified by `ptr`, such that it has a new size, specified by
+`new_size` and and is aligned on a boundary specified by `alignment`.
+
+If the `ptr` parameter is `nil`, `resize()` acts just like `alloc()`, allocating
+`new_size` bytes, aligned on a boundary specified by `alignment`.
+
+If the `new_size` parameter is `0`, `resize()` acts just like `free()`, freeing
+the memory region `old_size` bytes in length, located at the address specified
+by `ptr`.
+
+If the `old_memory` pointer is not aligned to the boundary specified by
+`alignment`, the procedure relocates the buffer such that the reallocated
+buffer is aligned to the boundary specified by `alignment`.
+
+**Inputs**:
+- `ptr`: Pointer to the memory region to resize.
+- `old_size`: Size of the memory region to resize.
+- `new_size`: The desired size of the resized memory region.
+- `alignment`: The desired alignment of the resized memory region.
+- `allocator`: The owner of the memory region to resize.
+
+**Returns**:
+1. The pointer to the resized memory region, if successfull, `nil` otherwise.
+2. Error, if resize failed.
+
+**Errors**:
+- `None`: No error.
+- `Out_Of_Memory`: When the allocator's backing buffer or it's backing
+ allocator does not have enough space to fit in an allocation with the new
+ size, or an operating system failure occurs.
+- `Invalid_Pointer`: The pointer referring to a memory region does not belong
+ to any of the allocators backing buffers or does not point to a valid start
+ of an allocation made in that allocator.
+- `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
+ or the `old_size` argument is incorrect.
+- `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
+
+**Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
+no-op, and should not return errors.
+*/
@(require_results)
-resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
+resize :: proc(
+ ptr: rawptr,
+ old_size: int,
+ new_size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
data, err := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
return raw_data(data), err
}
+/*
+Resize a memory region without zero-initialization.
+
+This procedure resizes a memory region, `old_size` bytes in size, located at
+the address specified by `ptr`, such that it has a new size, specified by
+`new_size` and and is aligned on a boundary specified by `alignment`.
+
+If the `ptr` parameter is `nil`, `resize()` acts just like `alloc()`, allocating
+`new_size` bytes, aligned on a boundary specified by `alignment`.
+
+If the `new_size` parameter is `0`, `resize()` acts just like `free()`, freeing
+the memory region `old_size` bytes in length, located at the address specified
+by `ptr`.
+
+If the `old_memory` pointer is not aligned to the boundary specified by
+`alignment`, the procedure relocates the buffer such that the reallocated
+buffer is aligned to the boundary specified by `alignment`.
+
+Unlike `resize()`, this procedure does not explicitly zero-initialize any new
+memory.
+
+**Inputs**:
+- `ptr`: Pointer to the memory region to resize.
+- `old_size`: Size of the memory region to resize.
+- `new_size`: The desired size of the resized memory region.
+- `alignment`: The desired alignment of the resized memory region.
+- `allocator`: The owner of the memory region to resize.
+
+**Returns**:
+1. The pointer to the resized memory region, if successfull, `nil` otherwise.
+2. Error, if resize failed.
+
+**Errors**:
+- `None`: No error.
+- `Out_Of_Memory`: When the allocator's backing buffer or it's backing
+ allocator does not have enough space to fit in an allocation with the new
+ size, or an operating system failure occurs.
+- `Invalid_Pointer`: The pointer referring to a memory region does not belong
+ to any of the allocators backing buffers or does not point to a valid start
+ of an allocation made in that allocator.
+- `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
+ or the `old_size` argument is incorrect.
+- `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
+
+**Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
+no-op, and should not return errors.
+*/
@(require_results)
-resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+resize_non_zeroed :: proc(
+ ptr: rawptr,
+ old_size: int,
+ new_size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ data, err := runtime.non_zero_mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
+ return raw_data(data), err
+}
+
+/*
+Resize a memory region.
+
+This procedure resizes a memory region, specified by `old_data`, such that it
+has a new size, specified by `new_size` and and is aligned on a boundary
+specified by `alignment`.
+
+If the `old_data` parameter is `nil`, `resize_bytes()` acts just like
+`alloc_bytes()`, allocating `new_size` bytes, aligned on a boundary specified
+by `alignment`.
+
+If the `new_size` parameter is `0`, `resize_bytes()` acts just like
+`free_bytes()`, freeing the memory region specified by `old_data`.
+
+If the `old_memory` pointer is not aligned to the boundary specified by
+`alignment`, the procedure relocates the buffer such that the reallocated
+buffer is aligned to the boundary specified by `alignment`.
+
+**Inputs**:
+- `old_data`: Pointer to the memory region to resize.
+- `new_size`: The desired size of the resized memory region.
+- `alignment`: The desired alignment of the resized memory region.
+- `allocator`: The owner of the memory region to resize.
+
+**Returns**:
+1. The resized memory region, if successfull, `nil` otherwise.
+2. Error, if resize failed.
+
+**Errors**:
+- `None`: No error.
+- `Out_Of_Memory`: When the allocator's backing buffer or it's backing
+ allocator does not have enough space to fit in an allocation with the new
+ size, or an operating system failure occurs.
+- `Invalid_Pointer`: The pointer referring to a memory region does not belong
+ to any of the allocators backing buffers or does not point to a valid start
+ of an allocation made in that allocator.
+- `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
+ or the `old_size` argument is incorrect.
+- `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
+
+**Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
+no-op, and should not return errors.
+*/
+@(require_results)
+resize_bytes :: proc(
+ old_data: []byte,
+ new_size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
}
+/*
+Resize a memory region.
+
+This procedure resizes a memory region, specified by `old_data`, such that it
+has a new size, specified by `new_size` and and is aligned on a boundary
+specified by `alignment`.
+
+If the `old_data` parameter is `nil`, `resize_bytes()` acts just like
+`alloc_bytes()`, allocating `new_size` bytes, aligned on a boundary specified
+by `alignment`.
+
+If the `new_size` parameter is `0`, `resize_bytes()` acts just like
+`free_bytes()`, freeing the memory region specified by `old_data`.
+
+If the `old_memory` pointer is not aligned to the boundary specified by
+`alignment`, the procedure relocates the buffer such that the reallocated
+buffer is aligned to the boundary specified by `alignment`.
+
+Unlike `resize_bytes()`, this procedure does not explicitly zero-initialize
+any new memory.
+
+**Inputs**:
+- `old_data`: Pointer to the memory region to resize.
+- `new_size`: The desired size of the resized memory region.
+- `alignment`: The desired alignment of the resized memory region.
+- `allocator`: The owner of the memory region to resize.
+
+**Returns**:
+1. The resized memory region, if successfull, `nil` otherwise.
+2. Error, if resize failed.
+
+**Errors**:
+- `None`: No error.
+- `Out_Of_Memory`: When the allocator's backing buffer or it's backing
+ allocator does not have enough space to fit in an allocation with the new
+ size, or an operating system failure occurs.
+- `Invalid_Pointer`: The pointer referring to a memory region does not belong
+ to any of the allocators backing buffers or does not point to a valid start
+ of an allocation made in that allocator.
+- `Invalid_Argument`: When `size` is negative, alignment is not a power of two,
+ or the `old_size` argument is incorrect.
+- `Mode_Not_Implemented`: The allocator does not support the `.Realloc` mode.
+
+**Note**: if `old_size` is `0` and `old_memory` is `nil`, this operation is a
+no-op, and should not return errors.
+*/
+@(require_results)
+resize_bytes_non_zeroed :: proc(
+ old_data: []byte,
+ new_size: int,
+ alignment: int = DEFAULT_ALIGNMENT,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ return runtime.non_zero_mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
+}
+
+/*
+Query allocator features.
+*/
@(require_results)
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil {
@@ -114,8 +716,15 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
return nil
}
+/*
+Query allocator information.
+*/
@(require_results)
-query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
+query_info :: proc(
+ pointer: rawptr,
+ allocator: Allocator,
+ loc := #caller_location,
+) -> (props: Allocator_Query_Info) {
props.pointer = pointer
if allocator.procedure != nil {
allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
@@ -123,25 +732,62 @@ query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_locatio
return
}
-
-
-delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
+/*
+Free a string.
+*/
+delete_string :: proc(
+ str: string,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.delete_string(str, allocator, loc)
}
-delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
+
+/*
+Free a cstring.
+*/
+delete_cstring :: proc(
+ str: cstring,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.delete_cstring(str, allocator, loc)
}
-delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
+
+/*
+Free a dynamic array.
+*/
+delete_dynamic_array :: proc(
+ array: $T/[dynamic]$E,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.delete_dynamic_array(array, loc)
}
-delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
+
+/*
+Free a slice.
+*/
+delete_slice :: proc(
+ array: $T/[]$E,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.delete_slice(array, allocator, loc)
}
-delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
+
+/*
+Free a map.
+*/
+delete_map :: proc(
+ m: $T/map[$K]$V,
+ loc := #caller_location,
+) -> Allocator_Error {
return runtime.delete_map(m, loc)
}
-
+/*
+Free.
+*/
delete :: proc{
delete_string,
delete_cstring,
@@ -150,49 +796,177 @@ delete :: proc{
delete_map,
}
+/*
+Allocate a new object.
+This procedure allocates a new object of type `T` using an allocator specified
+by `allocator`, and returns a pointer to the allocated object, if allocated
+successfully, or `nil` otherwise.
+*/
@(require_results)
-new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) {
+new :: proc(
+ $T: typeid,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (^T, Allocator_Error) {
return new_aligned(T, align_of(T), allocator, loc)
}
+
+/*
+Allocate a new object with alignment.
+
+This procedure allocates a new object of type `T` using an allocator specified
+by `allocator`, and returns a pointer, aligned on a boundary specified by
+`alignment` to the allocated object, if allocated successfully, or `nil`
+otherwise.
+*/
@(require_results)
-new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
+new_aligned :: proc(
+ $T: typeid,
+ alignment: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (t: ^T, err: Allocator_Error) {
return runtime.new_aligned(T, alignment, allocator, loc)
}
+
+/*
+Allocate a new object and initialize it with a value.
+
+This procedure allocates a new object of type `T` using an allocator specified
+by `allocator`, and returns a pointer, aligned on a boundary specified by
+`alignment` to the allocated object, if allocated successfully, or `nil`
+otherwise. The allocated object is initialized with `data`.
+*/
@(require_results)
-new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
+new_clone :: proc(
+ data: $T,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (t: ^T, err: Allocator_Error) {
return runtime.new_clone(data, allocator, loc)
}
+/*
+Allocate a new slice with alignment.
+
+This procedure allocates a new slice of type `T` with length `len`, aligned
+on a boundary specified by `alignment` from an allocator specified by
+`allocator`, and returns the allocated slice.
+*/
@(require_results)
-make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (slice: T, err: Allocator_Error) {
+make_aligned :: proc(
+ $T: typeid/[]$E,
+ #any_int len: int,
+ alignment: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (slice: T, err: Allocator_Error) {
return runtime.make_aligned(T, len, alignment, allocator, loc)
}
+
+/*
+Allocate a new slice.
+
+This procedure allocates a new slice of type `T` with length `len`, from an
+allocator specified by `allocator`, and returns the allocated slice.
+*/
@(require_results)
-make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
+make_slice :: proc(
+ $T: typeid/[]$E,
+ #any_int len: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (T, Allocator_Error) {
return runtime.make_slice(T, len, allocator, loc)
}
+
+/*
+Allocate a dynamic array.
+
+This procedure creates a dynamic array of type `T`, with `allocator` as its
+backing allocator, and initial length and capacity of `0`.
+*/
@(require_results)
-make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
+make_dynamic_array :: proc(
+ $T: typeid/[dynamic]$E,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (T, Allocator_Error) {
return runtime.make_dynamic_array(T, allocator, loc)
}
+
+/*
+Allocate a dynamic array with initial length.
+
+This procedure creates a dynamic array of type `T`, with `allocator` as its
+backing allocator, and initial capacity of `0`, and initial length specified by
+`len`.
+*/
@(require_results)
-make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) {
- return runtime.make_dynamic_array(T, len, allocator, loc)
+make_dynamic_array_len :: proc(
+ $T: typeid/[dynamic]$E,
+ #any_int len: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (T, Allocator_Error) {
+ return runtime.make_dynamic_array_len_cap(T, len, len, allocator, loc)
}
+
+/*
+Allocate a dynamic array with initial length and capacity.
+
+This procedure creates a dynamic array of type `T`, with `allocator` as its
+backing allocator, and initial capacity specified by `cap`, and initial length
+specified by `len`.
+*/
@(require_results)
-make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) {
- return runtime.make_dynamic_array(T, len, cap, allocator, loc)
+make_dynamic_array_len_cap :: proc(
+ $T: typeid/[dynamic]$E,
+ #any_int len: int,
+ #any_int cap: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (array: T, err: Allocator_Error) {
+ return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc)
}
+
+/*
+Allocate a map.
+
+This procedure creates a map of type `T` with initial capacity specified by
+`cap`, that is using an allocator specified by `allocator` as its backing
+allocator.
+*/
@(require_results)
-make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY, allocator := context.allocator, loc := #caller_location) -> (m: T, err: Allocator_Error) {
+make_map :: proc(
+ $T: typeid/map[$K]$E,
+ #any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (m: T, err: Allocator_Error) {
return runtime.make_map(T, cap, allocator, loc)
}
+
+/*
+Allocate a multi pointer.
+
+This procedure allocates a multipointer of type `T` pointing to `len` elements,
+from an allocator specified by `allocator`.
+*/
@(require_results)
-make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) {
+make_multi_pointer :: proc(
+ $T: typeid/[^]$E,
+ #any_int len: int,
+ allocator := context.allocator,
+ loc := #caller_location
+) -> (mp: T, err: Allocator_Error) {
return runtime.make_multi_pointer(T, len, allocator, loc)
}
+/*
+Allocate.
+*/
make :: proc{
make_slice,
make_dynamic_array,
@@ -202,26 +976,112 @@ make :: proc{
make_multi_pointer,
}
+/*
+Default resize procedure.
+
+When allocator does not support resize operation, but supports `.Alloc` and
+`.Free`, this procedure is used to implement allocator's default behavior on
+resize.
+The behavior of the function is as follows:
+
+- If `new_size` is `0`, the function acts like `free()`, freeing the memory
+ region of `old_size` bytes located at `old_memory`.
+- If `old_memory` is `nil`, the function acts like `alloc()`, allocating
+ `new_size` bytes of memory aligned on a boundary specified by `alignment`.
+- Otherwise, a new memory region of size `new_size` is allocated, then the
+ data from the old memory region is copied and the old memory region is
+ freed.
+*/
@(require_results)
-default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: rawptr, err: Allocator_Error) {
+default_resize_align :: proc(
+ old_memory: rawptr,
+ old_size: int,
+ new_size: int,
+ alignment: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> (res: rawptr, err: Allocator_Error) {
data: []byte
- data, err = default_resize_bytes_align(([^]byte)(old_memory)[:old_size], new_size, alignment, allocator, loc)
+ data, err = default_resize_bytes_align(
+ ([^]byte) (old_memory)[:old_size],
+ new_size,
+ alignment,
+ allocator,
+ loc,
+ )
res = raw_data(data)
return
}
+/*
+Default resize procedure.
+
+When allocator does not support resize operation, but supports
+`.Alloc_Non_Zeroed` and `.Free`, this procedure is used to implement allocator's
+default behavior on resize.
+
+Unlike `default_resize_align` no new memory is being explicitly
+zero-initialized.
+
+The behavior of the function is as follows:
+
+- If `new_size` is `0`, the function acts like `free()`, freeing the memory
+ region of `old_size` bytes located at `old_memory`.
+- If `old_memory` is `nil`, the function acts like `alloc()`, allocating
+ `new_size` bytes of memory aligned on a boundary specified by `alignment`.
+- Otherwise, a new memory region of size `new_size` is allocated, then the
+ data from the old memory region is copied and the old memory region is
+ freed.
+*/
@(require_results)
-default_resize_bytes_align_non_zeroed :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+default_resize_bytes_align_non_zeroed :: proc(
+ old_data: []byte,
+ new_size: int,
+ alignment: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
return _default_resize_bytes_align(old_data, new_size, alignment, false, allocator, loc)
}
+
+/*
+Default resize procedure.
+
+When allocator does not support resize operation, but supports `.Alloc` and
+`.Free`, this procedure is used to implement allocator's default behavior on
+resize.
+
+The behavior of the function is as follows:
+
+- If `new_size` is `0`, the function acts like `free()`, freeing the memory
+ region specified by `old_data`.
+- If `old_data` is `nil`, the function acts like `alloc()`, allocating
+ `new_size` bytes of memory aligned on a boundary specified by `alignment`.
+- Otherwise, a new memory region of size `new_size` is allocated, then the
+ data from the old memory region is copied and the old memory region is
+ freed.
+*/
@(require_results)
-default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+default_resize_bytes_align :: proc(
+ old_data: []byte,
+ new_size: int,
+ alignment: int,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
return _default_resize_bytes_align(old_data, new_size, alignment, true, allocator, loc)
}
@(require_results)
-_default_resize_bytes_align :: #force_inline proc(old_data: []byte, new_size, alignment: int, should_zero: bool, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
+_default_resize_bytes_align :: #force_inline proc(
+ old_data: []byte,
+ new_size: int,
+ alignment: int,
+ should_zero: bool,
+ allocator := context.allocator,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
old_memory := raw_data(old_data)
old_size := len(old_data)
if old_memory == nil {
@@ -231,16 +1091,13 @@ _default_resize_bytes_align :: #force_inline proc(old_data: []byte, new_size, al
return alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
}
}
-
if new_size == 0 {
err := free_bytes(old_data, allocator, loc)
return nil, err
}
-
- if new_size == old_size {
+ if new_size == old_size && is_aligned(old_memory, alignment) {
return old_data, .None
}
-
new_memory : []byte
err : Allocator_Error
if should_zero {
@@ -251,7 +1108,6 @@ _default_resize_bytes_align :: #force_inline proc(old_data: []byte, new_size, al
if new_memory == nil || err != nil {
return nil, err
}
-
runtime.copy(new_memory, old_data)
free_bytes(old_data, allocator, loc)
return new_memory, err
diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin
index a5b93ad05..d729b902c 100644
--- a/core/mem/allocators.odin
+++ b/core/mem/allocators.odin
@@ -3,12 +3,14 @@ package mem
import "base:intrinsics"
import "base:runtime"
-nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
- return nil, nil
-}
+/*
+Nil allocator.
+The `nil` allocator returns `nil` on every allocation attempt. This type of
+allocator can be used in scenarios where memory doesn't need to be allocated,
+but an attempt to allocate memory is not an error.
+*/
+@(require_results)
nil_allocator :: proc() -> Allocator {
return Allocator{
procedure = nil_allocator_proc,
@@ -16,8 +18,81 @@ nil_allocator :: proc() -> Allocator {
}
}
-// Custom allocators
+nil_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ return nil, nil
+}
+
+
+/*
+Panic allocator.
+
+The panic allocator is a type of allocator that panics on any allocation
+attempt. This type of allocator can be used in scenarios where memory should
+not be allocated, and an attempt to allocate memory is an error.
+*/
+@(require_results)
+panic_allocator :: proc() -> Allocator {
+ return Allocator{
+ procedure = panic_allocator_proc,
+ data = nil,
+ }
+}
+
+panic_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ switch mode {
+ case .Alloc:
+ if size > 0 {
+ panic("mem: panic allocator, .Alloc called", loc=loc)
+ }
+ case .Alloc_Non_Zeroed:
+ if size > 0 {
+ panic("mem: panic allocator, .Alloc_Non_Zeroed called", loc=loc)
+ }
+ case .Resize:
+ if size > 0 {
+ panic("mem: panic allocator, .Resize called", loc=loc)
+ }
+ case .Resize_Non_Zeroed:
+ if size > 0 {
+ panic("mem: panic allocator, .Resize_Non_Zeroed called", loc=loc)
+ }
+ case .Free:
+ if old_memory != nil {
+ panic("mem: panic allocator, .Free called", loc=loc)
+ }
+ case .Free_All:
+ panic("mem: panic allocator, .Free_All called", loc=loc)
+ case .Query_Features:
+ set := (^Allocator_Mode_Set)(old_memory)
+ if set != nil {
+ set^ = {.Query_Features}
+ }
+ return nil, nil
+
+ case .Query_Info:
+ panic("mem: panic allocator, .Query_Info called", loc=loc)
+ }
+ return nil, nil
+}
+
+/*
+Arena allocator data.
+*/
Arena :: struct {
data: []byte,
offset: int,
@@ -25,12 +100,39 @@ Arena :: struct {
temp_count: int,
}
-Arena_Temp_Memory :: struct {
- arena: ^Arena,
- prev_offset: int,
+/*
+Arena allocator.
+
+The arena allocator (also known as a linear allocator, bump allocator,
+region allocator) is an allocator that uses a single backing buffer for
+allocations.
+
+The buffer is being used contiguously, from start by end. Each subsequent
+allocation occupies the next adjacent region of memory in the buffer. Since
+arena allocator does not keep track of any metadata associated with the
+allocations and their locations, it is impossible to free individual
+allocations.
+
+The arena allocator can be used for temporary allocations in frame-based memory
+management. Games are one example of such applications. A global arena can be
+used for any temporary memory allocations, and at the end of each frame all
+temporary allocations are freed. Since no temporary object is going to live
+longer than a frame, no lifetimes are violated.
+*/
+@(require_results)
+arena_allocator :: proc(arena: ^Arena) -> Allocator {
+ return Allocator{
+ procedure = arena_allocator_proc,
+ data = arena,
+ }
}
+/*
+Initialize an arena.
+This procedure initializes the arena `a` with memory region `data` as it's
+backing buffer.
+*/
arena_init :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
@@ -46,64 +148,157 @@ init_arena :: proc(a: ^Arena, data: []byte) {
a.temp_count = 0
}
+/*
+Allocate memory from an arena.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from an arena `a`. The allocated memory is zero-initialized.
+This procedure returns a pointer to the newly allocated memory region.
+*/
@(require_results)
-arena_allocator :: proc(arena: ^Arena) -> Allocator {
- return Allocator{
- procedure = arena_allocator_proc,
- data = arena,
- }
+arena_alloc :: proc(
+ a: ^Arena,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := arena_alloc_bytes(a, size, alignment, loc)
+ return raw_data(bytes), err
}
-arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
- arena := cast(^Arena)allocator_data
+/*
+Allocate memory from an arena.
- switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- #no_bounds_check end := &arena.data[arena.offset]
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from an arena `a`. The allocated memory is zero-initialized.
+This procedure returns a slice of the newly allocated memory region.
+*/
+@(require_results)
+arena_alloc_bytes :: proc(
+ a: ^Arena,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := arena_alloc_bytes_non_zeroed(a, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
- ptr := align_forward(end, uintptr(alignment))
+/*
+Allocate non-initialized memory from an arena.
- total_size := size + ptr_sub((^byte)(ptr), (^byte)(end))
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from an arena `a`. The allocated memory is not explicitly
+zero-initialized. This procedure returns a pointer to the newly allocated
+memory region.
+*/
+@(require_results)
+arena_alloc_non_zeroed :: proc(
+ a: ^Arena,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := arena_alloc_bytes_non_zeroed(a, size, alignment, loc)
+ return raw_data(bytes), err
+}
- if arena.offset + total_size > len(arena.data) {
- return nil, .Out_Of_Memory
- }
+/*
+Allocate non-initialized memory from an arena.
- arena.offset += total_size
- arena.peak_used = max(arena.peak_used, arena.offset)
- if mode != .Alloc_Non_Zeroed {
- zero(ptr, size)
- }
- return byte_slice(ptr, size), nil
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from an arena `a`. The allocated memory is not explicitly
+zero-initialized. This procedure returns a slice of the newly allocated
+memory region.
+*/
+@(require_results)
+arena_alloc_bytes_non_zeroed :: proc(
+ a: ^Arena,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> ([]byte, Allocator_Error) {
+ if a.data == nil {
+ panic("Arena is not initialized", loc)
+ }
+ #no_bounds_check end := &a.data[a.offset]
+ ptr := align_forward(end, uintptr(alignment))
+ total_size := size + ptr_sub((^byte)(ptr), (^byte)(end))
+ if a.offset + total_size > len(a.data) {
+ return nil, .Out_Of_Memory
+ }
+ a.offset += total_size
+ a.peak_used = max(a.peak_used, a.offset)
+ return byte_slice(ptr, size), nil
+}
+
+/*
+Free all memory to an arena.
+*/
+arena_free_all :: proc(a: ^Arena) {
+ a.offset = 0
+}
+arena_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size: int,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ arena := cast(^Arena)allocator_data
+ switch mode {
+ case .Alloc:
+ return arena_alloc_bytes(arena, size, alignment, loc)
+ case .Alloc_Non_Zeroed:
+ return arena_alloc_bytes_non_zeroed(arena, size, alignment, loc)
case .Free:
return nil, .Mode_Not_Implemented
-
case .Free_All:
- arena.offset = 0
-
+ arena_free_all(arena)
case .Resize:
- return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena))
-
+ return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), loc)
case .Resize_Non_Zeroed:
- return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena))
-
+ return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
}
return nil, nil
-
case .Query_Info:
return nil, .Mode_Not_Implemented
}
-
return nil, nil
}
+/*
+Temporary memory region of arena.
+
+Temporary memory regions of arena act as "savepoints" for arena. When one is
+created, the subsequent allocations are done inside the temporary memory
+region. When `end_arena_temp_memory` is called, the arena is rolled back, and
+all of the memory that was allocated from the arena will be freed.
+
+Multiple temporary memory regions can exist at the same time for an arena.
+*/
+Arena_Temp_Memory :: struct {
+ arena: ^Arena,
+ prev_offset: int,
+}
+
+/*
+Start a temporary memory region.
+
+This procedure creates a temporary memory region. After a temporary memory
+region is created, all allocations are said to be *inside* the temporary memory
+region, until `end_arena_temp_memory` is called.
+*/
@(require_results)
begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
tmp: Arena_Temp_Memory
@@ -113,6 +308,12 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> Arena_Temp_Memory {
return tmp
}
+/*
+End a temporary memory region.
+
+This procedure ends the temporary memory region for an arena. All of the
+allocations *inside* the temporary memory region will be freed to the arena.
+*/
end_arena_temp_memory :: proc(tmp: Arena_Temp_Memory) {
assert(tmp.arena.offset >= tmp.prev_offset)
assert(tmp.arena.temp_count > 0)
@@ -120,9 +321,15 @@ end_arena_temp_memory :: proc(tmp: Arena_Temp_Memory) {
tmp.arena.temp_count -= 1
}
+/* Preserved for compatibility */
+Scratch_Allocator :: Scratch
+scratch_allocator_init :: scratch_init
+scratch_allocator_destroy :: scratch_destroy
-
-Scratch_Allocator :: struct {
+/*
+Scratch allocator data.
+*/
+Scratch :: struct {
data: []byte,
curr_offset: int,
prev_allocation: rawptr,
@@ -130,7 +337,35 @@ Scratch_Allocator :: struct {
leaked_allocations: [dynamic][]byte,
}
-scratch_allocator_init :: proc(s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) -> Allocator_Error {
+/*
+Scratch allocator.
+
+The scratch allocator works in a similar way to the `Arena` allocator. The
+scratch allocator has a backing buffer, that is being allocated in
+contiguous regions, from start to end.
+
+Each subsequent allocation will be the next adjacent region of memory in the
+backing buffer. If the allocation doesn't fit into the remaining space of the
+backing buffer, this allocation is put at the start of the buffer, and all
+previous allocations will become invalidated. If the allocation doesn't fit
+into the backing buffer as a whole, it will be allocated using a backing
+allocator, and pointer to the allocated memory region will be put into the
+`leaked_allocations` array.
+
+The `leaked_allocations` array is managed by the `context` allocator.
+*/
+@(require_results)
+scratch_allocator :: proc(allocator: ^Scratch) -> Allocator {
+ return Allocator{
+ procedure = scratch_allocator_proc,
+ data = allocator,
+ }
+}
+
+/*
+Initialize scratch allocator.
+*/
+scratch_init :: proc(s: ^Scratch, size: int, backup_allocator := context.allocator) -> Allocator_Error {
s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator) or_return
s.curr_offset = 0
s.prev_allocation = nil
@@ -139,7 +374,10 @@ scratch_allocator_init :: proc(s: ^Scratch_Allocator, size: int, backup_allocato
return nil
}
-scratch_allocator_destroy :: proc(s: ^Scratch_Allocator) {
+/*
+Free all data associated with a scratch allocator.
+*/
+scratch_destroy :: proc(s: ^Scratch) {
if s == nil {
return
}
@@ -151,60 +389,105 @@ scratch_allocator_destroy :: proc(s: ^Scratch_Allocator) {
s^ = {}
}
-scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
+/*
+Allocate memory from scratch allocator.
- s := (^Scratch_Allocator)(allocator_data)
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is zero-initialized. This procedure
+returns a pointer to the allocated memory region.
+*/
+@(require_results)
+scratch_alloc :: proc(
+ s: ^Scratch,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := scratch_alloc_bytes(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
- if s.data == nil {
- DEFAULT_BACKING_SIZE :: 4 * Megabyte
- if !(context.allocator.procedure != scratch_allocator_proc &&
- context.allocator.data != allocator_data) {
- panic("cyclic initialization of the scratch allocator with itself")
- }
- scratch_allocator_init(s, DEFAULT_BACKING_SIZE)
- }
+/*
+Allocate memory from scratch allocator.
- size := size
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is zero-initialized. This procedure
+returns a slice of the allocated memory region.
+*/
+@(require_results)
+scratch_alloc_bytes :: proc(
+ s: ^Scratch,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := scratch_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
- switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- size = align_forward_int(size, alignment)
-
- switch {
- case s.curr_offset+size <= len(s.data):
- start := uintptr(raw_data(s.data))
- ptr := start + uintptr(s.curr_offset)
- ptr = align_forward_uintptr(ptr, uintptr(alignment))
- if mode != .Alloc_Non_Zeroed {
- zero(rawptr(ptr), size)
- }
+/*
+Allocate non-initialized memory from scratch allocator.
- s.prev_allocation = rawptr(ptr)
- offset := int(ptr - start)
- s.curr_offset = offset + size
- return byte_slice(rawptr(ptr), size), nil
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is not explicitly zero-initialized.
+This procedure returns a pointer to the allocated memory region.
+*/
+@(require_results)
+scratch_alloc_non_zeroed :: proc(
+ s: ^Scratch,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := scratch_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
- case size <= len(s.data):
- start := uintptr(raw_data(s.data))
- ptr := align_forward_uintptr(start, uintptr(alignment))
- if mode != .Alloc_Non_Zeroed {
- zero(rawptr(ptr), size)
- }
+/*
+Allocate non-initialized memory from scratch allocator.
- s.prev_allocation = rawptr(ptr)
- offset := int(ptr - start)
- s.curr_offset = offset + size
- return byte_slice(rawptr(ptr), size), nil
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is not explicitly zero-initialized.
+This procedure returns a slice of the allocated memory region.
+*/
+@(require_results)
+scratch_alloc_bytes_non_zeroed :: proc(
+ s: ^Scratch,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ if s.data == nil {
+ DEFAULT_BACKING_SIZE :: 4 * Megabyte
+ if !(context.allocator.procedure != scratch_allocator_proc && context.allocator.data != s) {
+ panic("cyclic initialization of the scratch allocator with itself", loc)
}
+ scratch_init(s, DEFAULT_BACKING_SIZE)
+ }
+ size := size
+ size = align_forward_int(size, alignment)
+ if size <= len(s.data) {
+ offset := uintptr(0)
+ if s.curr_offset+size <= len(s.data) {
+ offset = uintptr(s.curr_offset)
+ } else {
+ offset = 0
+ }
+ start := uintptr(raw_data(s.data))
+ ptr := align_forward_uintptr(offset+start, uintptr(alignment))
+ s.prev_allocation = rawptr(ptr)
+ s.curr_offset = int(offset) + size
+ return byte_slice(rawptr(ptr), size), nil
+ } else {
a := s.backup_allocator
if a.procedure == nil {
a = context.allocator
s.backup_allocator = a
}
-
- ptr, err := alloc_bytes(size, alignment, a, loc)
+ ptr, err := alloc_bytes_non_zeroed(size, alignment, a, loc)
if err != nil {
return ptr, err
}
@@ -212,110 +495,290 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
s.leaked_allocations, err = make([dynamic][]byte, a)
}
append(&s.leaked_allocations, ptr)
-
if logger := context.logger; logger.lowest_level <= .Warning {
if logger.procedure != nil {
- logger.procedure(logger.data, .Warning, "mem.Scratch_Allocator resorted to backup_allocator" , logger.options, loc)
+ logger.procedure(logger.data, .Warning, "mem.Scratch resorted to backup_allocator" , logger.options, loc)
}
}
-
return ptr, err
+ }
+}
- case .Free:
- if old_memory == nil {
- return nil, nil
- }
- start := uintptr(raw_data(s.data))
- end := start + uintptr(len(s.data))
- old_ptr := uintptr(old_memory)
-
- if s.prev_allocation == old_memory {
- s.curr_offset = int(uintptr(s.prev_allocation) - start)
- s.prev_allocation = nil
- return nil, nil
- }
+/*
+Free memory to the scratch allocator.
- if start <= old_ptr && old_ptr < end {
- // NOTE(bill): Cannot free this pointer but it is valid
- return nil, nil
- }
+This procedure frees the memory region allocated at pointer `ptr`.
- if len(s.leaked_allocations) != 0 {
- for data, i in s.leaked_allocations {
- ptr := raw_data(data)
- if ptr == old_memory {
- free_bytes(data, s.backup_allocator)
- ordered_remove(&s.leaked_allocations, i)
- return nil, nil
- }
+If `ptr` is not the latest allocation and is not a leaked allocation, this
+operation is a no-op.
+*/
+scratch_free :: proc(s: ^Scratch, ptr: rawptr, loc := #caller_location) -> Allocator_Error {
+ if s.data == nil {
+ panic("Free on an uninitialized scratch allocator", loc)
+ }
+ if ptr == nil {
+ return nil
+ }
+ start := uintptr(raw_data(s.data))
+ end := start + uintptr(len(s.data))
+ old_ptr := uintptr(ptr)
+ if s.prev_allocation == ptr {
+ s.curr_offset = int(uintptr(s.prev_allocation) - start)
+ s.prev_allocation = nil
+ return nil
+ }
+ if start <= old_ptr && old_ptr < end {
+ // NOTE(bill): Cannot free this pointer but it is valid
+ return nil
+ }
+ if len(s.leaked_allocations) != 0 {
+ for data, i in s.leaked_allocations {
+ ptr := raw_data(data)
+ if ptr == ptr {
+ free_bytes(data, s.backup_allocator, loc)
+ ordered_remove(&s.leaked_allocations, i, loc)
+ return nil
}
}
- return nil, .Invalid_Pointer
- // panic("invalid pointer passed to default_temp_allocator");
+ }
+ return .Invalid_Pointer
+}
- case .Free_All:
- s.curr_offset = 0
- s.prev_allocation = nil
- for ptr in s.leaked_allocations {
- free_bytes(ptr, s.backup_allocator)
- }
- clear(&s.leaked_allocations)
+/*
+Free all memory to the scratch allocator.
+*/
+scratch_free_all :: proc(s: ^Scratch, loc := #caller_location) {
+ s.curr_offset = 0
+ s.prev_allocation = nil
+ for ptr in s.leaked_allocations {
+ free_bytes(ptr, s.backup_allocator, loc)
+ }
+ clear(&s.leaked_allocations)
+}
- case .Resize, .Resize_Non_Zeroed:
- begin := uintptr(raw_data(s.data))
- end := begin + uintptr(len(s.data))
- old_ptr := uintptr(old_memory)
- if begin <= old_ptr && old_ptr < end && old_ptr+uintptr(size) < end {
- s.curr_offset = int(old_ptr-begin)+size
- return byte_slice(old_memory, size), nil
- }
- data, err := scratch_allocator_proc(allocator_data, .Alloc, size, alignment, old_memory, old_size, loc)
- if err != nil {
- return data, err
+/*
+Resize an allocation.
+
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `scratch_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+scratch_resize :: proc(
+ s: ^Scratch,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> (rawptr, Allocator_Error) {
+ bytes, err := scratch_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Resize an allocation.
+
+This procedure resizes a memory region, specified by `old_data`, to have a size
+`size` and alignment `alignment`. The newly allocated memory, if any is
+zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `scratch_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+scratch_resize_bytes :: proc(
+ s: ^Scratch,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> ([]byte, Allocator_Error) {
+ bytes, err := scratch_resize_bytes_non_zeroed(s, old_data, size, alignment, loc)
+ if bytes != nil && size > len(old_data) {
+ zero_slice(bytes[size:])
+ }
+ return bytes, err
+}
+
+/*
+Resize an allocation without zero-initialization.
+
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is not explicitly zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `scratch_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+scratch_resize_non_zeroed :: proc(
+ s: ^Scratch,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> (rawptr, Allocator_Error) {
+ bytes, err := scratch_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Resize an allocation.
+
+This procedure resizes a memory region, specified by `old_data`, to have a size
+`size` and alignment `alignment`. The newly allocated memory, if any is not
+explicitly zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `scratch_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+scratch_resize_bytes_non_zeroed :: proc(
+ s: ^Scratch,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> ([]byte, Allocator_Error) {
+ old_memory := raw_data(old_data)
+ old_size := len(old_data)
+ if s.data == nil {
+ DEFAULT_BACKING_SIZE :: 4 * Megabyte
+ if !(context.allocator.procedure != scratch_allocator_proc && context.allocator.data != s) {
+ panic("cyclic initialization of the scratch allocator with itself", loc)
}
- runtime.copy(data, byte_slice(old_memory, old_size))
- _, err = scratch_allocator_proc(allocator_data, .Free, 0, alignment, old_memory, old_size, loc)
+ scratch_init(s, DEFAULT_BACKING_SIZE)
+ }
+ begin := uintptr(raw_data(s.data))
+ end := begin + uintptr(len(s.data))
+ old_ptr := uintptr(old_memory)
+ if begin <= old_ptr && old_ptr < end && old_ptr+uintptr(size) < end {
+ s.curr_offset = int(old_ptr-begin)+size
+ return byte_slice(old_memory, size), nil
+ }
+ data, err := scratch_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if err != nil {
return data, err
+ }
+ runtime.copy(data, byte_slice(old_memory, old_size))
+ err = scratch_free(s, old_memory, loc)
+ return data, err
+}
+scratch_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ s := (^Scratch)(allocator_data)
+ size := size
+ switch mode {
+ case .Alloc:
+ return scratch_alloc_bytes(s, size, alignment, loc)
+ case .Alloc_Non_Zeroed:
+ return scratch_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ case .Free:
+ return nil, scratch_free(s, old_memory, loc)
+ case .Free_All:
+ scratch_free_all(s, loc)
+ case .Resize:
+ return scratch_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ case .Resize_Non_Zeroed:
+ return scratch_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment, loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
}
return nil, nil
-
case .Query_Info:
return nil, .Mode_Not_Implemented
}
-
return nil, nil
}
-@(require_results)
-scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> Allocator {
- return Allocator{
- procedure = scratch_allocator_proc,
- data = allocator,
- }
-}
-
-
+/*
+Stack allocator data.
+*/
+Stack :: struct {
+ data: []byte,
+ prev_offset: int,
+ curr_offset: int,
+ peak_used: int,
+}
+/*
+Header of a stack allocation.
+*/
Stack_Allocation_Header :: struct {
prev_offset: int,
padding: int,
}
-// Stack is a stack-like allocator which has a strict memory freeing order
-Stack :: struct {
- data: []byte,
- prev_offset: int,
- curr_offset: int,
- peak_used: int,
+/*
+Stack allocator.
+
+The stack allocator is an allocator that allocates data in the backing buffer
+linearly, from start to end. Each subsequent allocation will get the next
+adjacent memory region.
+
+Unlike arena allocator, the stack allocator saves allocation metadata and has
+a strict freeing order. Only the last allocated element can be freed. After the
+last allocated element is freed, the next previous allocated element becomes
+available for freeing.
+
+The metadata is stored in the allocation headers, that are located before the
+start of each allocated memory region. Each header points to the start of the
+previous allocation header.
+*/
+@(require_results)
+stack_allocator :: proc(stack: ^Stack) -> Allocator {
+ return Allocator{
+ procedure = stack_allocator_proc,
+ data = stack,
+ }
}
+/*
+Initialize the stack allocator.
+
+This procedure initializes the stack allocator with a backing buffer specified
+by `data` parameter.
+*/
stack_init :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
@@ -331,129 +794,333 @@ init_stack :: proc(s: ^Stack, data: []byte) {
s.peak_used = 0
}
+/*
+Allocate memory from stack.
+
+This procedure allocates `size` bytes of memory, aligned to the boundary
+specified by `alignment`. The allocated memory is zero-initialized. This
+procedure returns the pointer to the allocated memory.
+*/
@(require_results)
-stack_allocator :: proc(stack: ^Stack) -> Allocator {
- return Allocator{
- procedure = stack_allocator_proc,
- data = stack,
+stack_alloc :: proc(
+ s: ^Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> (rawptr, Allocator_Error) {
+ bytes, err := stack_alloc_bytes(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Allocate memory from stack.
+
+This procedure allocates `size` bytes of memory, aligned to the boundary
+specified by `alignment`. The allocated memory is zero-initialized. This
+procedure returns the slice of the allocated memory.
+*/
+@(require_results)
+stack_alloc_bytes :: proc(
+ s: ^Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> ([]byte, Allocator_Error) {
+ bytes, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
}
+ return bytes, err
}
+/*
+Allocate memory from stack.
-stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
- s := cast(^Stack)allocator_data
+This procedure allocates `size` bytes of memory, aligned to the boundary
+specified by `alignment`. The allocated memory is not explicitly
+zero-initialized. This procedure returns the pointer to the allocated memory.
+*/
+@(require_results)
+stack_alloc_non_zeroed :: proc(
+ s: ^Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> (rawptr, Allocator_Error) {
+ bytes, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Allocate memory from stack.
+This procedure allocates `size` bytes of memory, aligned to the boundary
+specified by `alignment`. The allocated memory is not explicitly
+zero-initialized. This procedure returns the slice of the allocated memory.
+*/
+@(require_results)
+stack_alloc_bytes_non_zeroed :: proc(
+ s: ^Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location
+) -> ([]byte, Allocator_Error) {
if s.data == nil {
- return nil, .Invalid_Argument
+ panic("Stack allocation on an uninitialized stack allocator", loc)
}
+ curr_addr := uintptr(raw_data(s.data)) + uintptr(s.curr_offset)
+ padding := calc_padding_with_header(
+ curr_addr,
+ uintptr(alignment),
+ size_of(Stack_Allocation_Header),
+ )
+ if s.curr_offset + padding + size > len(s.data) {
+ return nil, .Out_Of_Memory
+ }
+ s.prev_offset = s.curr_offset
+ s.curr_offset += padding
+ next_addr := curr_addr + uintptr(padding)
+ header := (^Stack_Allocation_Header)(next_addr - size_of(Stack_Allocation_Header))
+ header.padding = padding
+ header.prev_offset = s.prev_offset
+ s.curr_offset += size
+ s.peak_used = max(s.peak_used, s.curr_offset)
+ return byte_slice(rawptr(next_addr), size), nil
+}
- raw_alloc :: proc(s: ^Stack, size, alignment: int, zero_memory: bool) -> ([]byte, Allocator_Error) {
- curr_addr := uintptr(raw_data(s.data)) + uintptr(s.curr_offset)
- padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Stack_Allocation_Header))
- if s.curr_offset + padding + size > len(s.data) {
- return nil, .Out_Of_Memory
- }
- s.prev_offset = s.curr_offset
- s.curr_offset += padding
-
- next_addr := curr_addr + uintptr(padding)
- header := (^Stack_Allocation_Header)(next_addr - size_of(Stack_Allocation_Header))
- header.padding = padding
- header.prev_offset = s.prev_offset
+/*
+Free memory to the stack.
+
+This procedure frees the memory region starting at `old_memory` to the stack.
+If the freeing does is an out of order freeing, the `.Invalid_Pointer` error
+is returned.
+*/
+stack_free :: proc(
+ s: ^Stack,
+ old_memory: rawptr,
+ loc := #caller_location,
+) -> (Allocator_Error) {
+ if s.data == nil {
+ panic("Stack free on an uninitialized stack allocator", loc)
+ }
+ if old_memory == nil {
+ return nil
+ }
+ start := uintptr(raw_data(s.data))
+ end := start + uintptr(len(s.data))
+ curr_addr := uintptr(old_memory)
+ if !(start <= curr_addr && curr_addr < end) {
+ panic("Out of bounds memory address passed to stack allocator (free)", loc)
+ }
+ if curr_addr >= start+uintptr(s.curr_offset) {
+ // NOTE(bill): Allow double frees
+ return nil
+ }
+ header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header))
+ old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+ if old_offset != header.prev_offset {
+ // panic("Out of order stack allocator free");
+ return .Invalid_Pointer
+ }
+ s.curr_offset = old_offset
+ s.prev_offset = header.prev_offset
+ return nil
+}
- s.curr_offset += size
+/*
+Free all allocations to the stack.
+*/
+stack_free_all :: proc(s: ^Stack, loc := #caller_location) {
+ s.prev_offset = 0
+ s.curr_offset = 0
+}
- s.peak_used = max(s.peak_used, s.curr_offset)
+/*
+Resize an allocation.
- if zero_memory {
- zero(rawptr(next_addr), size)
- }
- return byte_slice(rawptr(next_addr), size), nil
- }
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is zero-initialized.
- switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- return raw_alloc(s, size, alignment, mode == .Alloc)
- case .Free:
- if old_memory == nil {
- return nil, nil
- }
- start := uintptr(raw_data(s.data))
- end := start + uintptr(len(s.data))
- curr_addr := uintptr(old_memory)
+If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- if !(start <= curr_addr && curr_addr < end) {
- panic("Out of bounds memory address passed to stack allocator (free)")
- }
+If `size` is 0, this procedure acts just like `stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
- if curr_addr >= start+uintptr(s.curr_offset) {
- // NOTE(bill): Allow double frees
- return nil, nil
- }
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+stack_resize :: proc(
+ s: ^Stack,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := stack_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment)
+ return raw_data(bytes), err
+}
- header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header))
- old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+/*
+Resize an allocation.
- if old_offset != header.prev_offset {
- // panic("Out of order stack allocator free");
- return nil, .Invalid_Pointer
- }
+This procedure resizes a memory region, specified by the `old_data` parameter
+to have a size `size` and alignment `alignment`. The newly allocated memory,
+if any is zero-initialized.
- s.curr_offset = old_offset
- s.prev_offset = header.prev_offset
+If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- case .Free_All:
- s.prev_offset = 0
- s.curr_offset = 0
+If `size` is 0, this procedure acts just like `stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
- case .Resize, .Resize_Non_Zeroed:
- if old_memory == nil {
- return raw_alloc(s, size, alignment, mode == .Resize)
- }
- if size == 0 {
- return nil, nil
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+stack_resize_bytes :: proc(
+ s: ^Stack,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if bytes != nil {
+ if old_data == nil {
+ zero_slice(bytes)
+ } else if size > len(old_data) {
+ zero_slice(bytes[len(old_data):])
}
+ }
+ return bytes, err
+}
- start := uintptr(raw_data(s.data))
- end := start + uintptr(len(s.data))
- curr_addr := uintptr(old_memory)
- if !(start <= curr_addr && curr_addr < end) {
- panic("Out of bounds memory address passed to stack allocator (resize)")
- }
+/*
+Resize an allocation without zero-initialization.
- if curr_addr >= start+uintptr(s.curr_offset) {
- // NOTE(bill): Allow double frees
- return nil, nil
- }
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is not explicitly zero-initialized.
- if old_size == size {
- return byte_slice(old_memory, size), nil
- }
+If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header))
- old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+If `size` is 0, this procedure acts just like `stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
- if old_offset != header.prev_offset {
- data, err := raw_alloc(s, size, alignment, mode == .Resize)
- if err == nil {
- runtime.copy(data, byte_slice(old_memory, old_size))
- }
- return data, err
- }
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+stack_resize_non_zeroed :: proc(
+ s: ^Stack,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := stack_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment)
+ return raw_data(bytes), err
+}
- old_memory_size := uintptr(s.curr_offset) - (curr_addr - start)
- assert(old_memory_size == uintptr(old_size))
+/*
+Resize an allocation without zero-initialization.
- diff := size - old_size
- s.curr_offset += diff // works for smaller sizes too
- if diff > 0 {
- zero(rawptr(curr_addr + uintptr(diff)), diff)
- }
+This procedure resizes a memory region, specified by the `old_data` parameter
+to have a size `size` and alignment `alignment`. The newly allocated memory,
+if any is not explicitly zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+If `size` is 0, this procedure acts just like `stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+stack_resize_bytes_non_zeroed :: proc(
+ s: ^Stack,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ old_memory := raw_data(old_data)
+ old_size := len(old_data)
+ if s.data == nil {
+ panic("Stack free all on an uninitialized stack allocator", loc)
+ }
+ if old_memory == nil {
+ return stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ }
+ if size == 0 {
+ return nil, nil
+ }
+ start := uintptr(raw_data(s.data))
+ end := start + uintptr(len(s.data))
+ curr_addr := uintptr(old_memory)
+ if !(start <= curr_addr && curr_addr < end) {
+ panic("Out of bounds memory address passed to stack allocator (resize)")
+ }
+ if curr_addr >= start+uintptr(s.curr_offset) {
+ // NOTE(bill): Allow double frees
+ return nil, nil
+ }
+ if old_size == size {
return byte_slice(old_memory, size), nil
+ }
+ header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header))
+ old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+ if old_offset != header.prev_offset {
+ data, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if err == nil {
+ runtime.copy(data, byte_slice(old_memory, old_size))
+ }
+ return data, err
+ }
+ old_memory_size := uintptr(s.curr_offset) - (curr_addr - start)
+ assert(old_memory_size == uintptr(old_size))
+ diff := size - old_size
+ s.curr_offset += diff // works for smaller sizes too
+ if diff > 0 {
+ zero(rawptr(curr_addr + uintptr(diff)), diff)
+ }
+ return byte_slice(old_memory, size), nil
+}
+stack_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size: int,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ s := cast(^Stack)allocator_data
+ if s.data == nil {
+ return nil, .Invalid_Argument
+ }
+ switch mode {
+ case .Alloc:
+ return stack_alloc_bytes(s, size, alignment, loc)
+ case .Alloc_Non_Zeroed:
+ return stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ case .Free:
+ return nil, stack_free(s, old_memory, loc)
+ case .Free_All:
+ stack_free_all(s, loc)
+ case .Resize:
+ return stack_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ case .Resize_Non_Zeroed:
+ return stack_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment, loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
@@ -463,27 +1130,32 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Query_Info:
return nil, .Mode_Not_Implemented
}
-
return nil, nil
}
-
-
-
-
-
+/*
+Allocation header of the small stack allocator.
+*/
Small_Stack_Allocation_Header :: struct {
padding: u8,
}
-// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
+/*
+Small stack allocator data.
+*/
Small_Stack :: struct {
data: []byte,
offset: int,
peak_used: int,
}
+/*
+Initialize small stack.
+
+This procedure initializes the small stack allocator with `data` as its backing
+buffer.
+*/
small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
@@ -497,6 +1169,20 @@ init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.peak_used = 0
}
+/*
+Small stack allocator.
+
+The small stack allocator is just like a stack allocator, with the only
+difference being an extremely small header size. Unlike the stack allocator,
+small stack allows out-of order freeing of memory.
+
+The memory is allocated in the backing buffer linearly, from start to end.
+Each subsequent allocation will get the next adjacent memory region.
+
+The metadata is stored in the allocation headers, that are located before the
+start of each allocated memory region. Each header contains the amount of
+padding bytes between that header and end of the previous allocation.
+*/
@(require_results)
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{
@@ -505,375 +1191,766 @@ small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
}
}
-small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
- s := cast(^Small_Stack)allocator_data
+/*
+Allocate memory from small stack.
- if s.data == nil {
- return nil, .Invalid_Argument
- }
+This procedure allocates `size` bytes of memory aligned to a boundary specified
+by `alignment`. The allocated memory is zero-initialized. This procedure
+returns a pointer to the allocated memory region.
+*/
+@(require_results)
+small_stack_alloc :: proc(
+ s: ^Small_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := small_stack_alloc_bytes(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
- align := clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2)
+/*
+Allocate memory from small stack.
- raw_alloc :: proc(s: ^Small_Stack, size, alignment: int, zero_memory: bool) -> ([]byte, Allocator_Error) {
- curr_addr := uintptr(raw_data(s.data)) + uintptr(s.offset)
- padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header))
- if s.offset + padding + size > len(s.data) {
- return nil, .Out_Of_Memory
- }
- s.offset += padding
+This procedure allocates `size` bytes of memory aligned to a boundary specified
+by `alignment`. The allocated memory is zero-initialized. This procedure
+returns a slice of the allocated memory region.
+*/
+@(require_results)
+small_stack_alloc_bytes :: proc(
+ s: ^Small_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
- next_addr := curr_addr + uintptr(padding)
- header := (^Small_Stack_Allocation_Header)(next_addr - size_of(Small_Stack_Allocation_Header))
- header.padding = auto_cast padding
+/*
+Allocate memory from small stack.
- s.offset += size
+This procedure allocates `size` bytes of memory aligned to a boundary specified
+by `alignment`. The allocated memory is not explicitly zero-initialized. This
+procedure returns a pointer to the allocated memory region.
+*/
+@(require_results)
+small_stack_alloc_non_zeroed :: proc(
+ s: ^Small_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ return raw_data(bytes), err
+}
- s.peak_used = max(s.peak_used, s.offset)
+/*
+Allocate memory from small stack.
- if zero_memory {
- zero(rawptr(next_addr), size)
- }
- return byte_slice(rawptr(next_addr), size), nil
+This procedure allocates `size` bytes of memory aligned to a boundary specified
+by `alignment`. The allocated memory is not explicitly zero-initialized. This
+procedure returns a slice of the allocated memory region.
+*/
+@(require_results)
+small_stack_alloc_bytes_non_zeroed :: proc(
+ s: ^Small_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ if s.data == nil {
+ panic("Small stack is not initialized", loc)
}
+ alignment := alignment
+ alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2)
+ curr_addr := uintptr(raw_data(s.data)) + uintptr(s.offset)
+ padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header))
+ if s.offset + padding + size > len(s.data) {
+ return nil, .Out_Of_Memory
+ }
+ s.offset += padding
+ next_addr := curr_addr + uintptr(padding)
+ header := (^Small_Stack_Allocation_Header)(next_addr - size_of(Small_Stack_Allocation_Header))
+ header.padding = auto_cast padding
+ s.offset += size
+ s.peak_used = max(s.peak_used, s.offset)
+ return byte_slice(rawptr(next_addr), size), nil
+}
- switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- return raw_alloc(s, size, align, mode == .Alloc)
- case .Free:
- if old_memory == nil {
- return nil, nil
- }
- start := uintptr(raw_data(s.data))
- end := start + uintptr(len(s.data))
- curr_addr := uintptr(old_memory)
+/*
+Allocate memory from small stack.
+
+This procedure allocates `size` bytes of memory aligned to a boundary specified
+by `alignment`. The allocated memory is not explicitly zero-initialized. This
+procedure returns a slice of the allocated memory region.
+*/
+small_stack_free :: proc(
+ s: ^Small_Stack,
+ old_memory: rawptr,
+ loc := #caller_location,
+) -> Allocator_Error {
+ if s.data == nil {
+ panic("Small stack is not initialized", loc)
+ }
+ if old_memory == nil {
+ return nil
+ }
+ start := uintptr(raw_data(s.data))
+ end := start + uintptr(len(s.data))
+ curr_addr := uintptr(old_memory)
+ if !(start <= curr_addr && curr_addr < end) {
+ // panic("Out of bounds memory address passed to stack allocator (free)");
+ return .Invalid_Pointer
+ }
+ if curr_addr >= start+uintptr(s.offset) {
+ // NOTE(bill): Allow double frees
+ return nil
+ }
+ header := (^Small_Stack_Allocation_Header)(curr_addr - size_of(Small_Stack_Allocation_Header))
+ old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+ s.offset = old_offset
+ return nil
+}
- if !(start <= curr_addr && curr_addr < end) {
- // panic("Out of bounds memory address passed to stack allocator (free)");
- return nil, .Invalid_Pointer
- }
+/*
+Free all memory to small stack.
+*/
+small_stack_free_all :: proc(s: ^Small_Stack) {
+ s.offset = 0
+}
- if curr_addr >= start+uintptr(s.offset) {
- // NOTE(bill): Allow double frees
- return nil, nil
- }
+/*
+Resize an allocation.
- header := (^Small_Stack_Allocation_Header)(curr_addr - size_of(Small_Stack_Allocation_Header))
- old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is zero-initialized.
- s.offset = old_offset
+If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- case .Free_All:
- s.offset = 0
+If `size` is 0, this procedure acts just like `small_stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
- case .Resize, .Resize_Non_Zeroed:
- if old_memory == nil {
- return raw_alloc(s, size, align, mode == .Resize)
- }
- if size == 0 {
- return nil, nil
- }
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+small_stack_resize :: proc(
+ s: ^Small_Stack,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := small_stack_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ return raw_data(bytes), err
+}
- start := uintptr(raw_data(s.data))
- end := start + uintptr(len(s.data))
- curr_addr := uintptr(old_memory)
- if !(start <= curr_addr && curr_addr < end) {
- // panic("Out of bounds memory address passed to stack allocator (resize)");
- return nil, .Invalid_Pointer
- }
+/*
+Resize an allocation.
- if curr_addr >= start+uintptr(s.offset) {
- // NOTE(bill): Treat as a double free
- return nil, nil
- }
+This procedure resizes a memory region, specified by the `old_data` parameter
+to have a size `size` and alignment `alignment`. The newly allocated memory,
+if any is zero-initialized.
- if old_size == size {
- return byte_slice(old_memory, size), nil
- }
+If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- data, err := raw_alloc(s, size, align, mode == .Resize)
- if err == nil {
- runtime.copy(data, byte_slice(old_memory, old_size))
- }
- return data, err
+If `size` is 0, this procedure acts just like `small_stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
- case .Query_Features:
- set := (^Allocator_Mode_Set)(old_memory)
- if set != nil {
- set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+small_stack_resize_bytes :: proc(
+ s: ^Small_Stack,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := small_stack_resize_bytes_non_zeroed(s, old_data, size, alignment, loc)
+ if bytes != nil {
+ if old_data == nil {
+ zero_slice(bytes)
+ } else if size > len(old_data) {
+ zero_slice(bytes[len(old_data):])
}
- return nil, nil
-
- case .Query_Info:
- return nil, .Mode_Not_Implemented
}
-
- return nil, nil
+ return bytes, err
}
+/*
+Resize an allocation without zero-initialization.
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is not explicitly zero-initialized.
+If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+If `size` is 0, this procedure acts just like `small_stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
-Dynamic_Pool :: struct {
- block_size: int,
- out_band_size: int,
- alignment: int,
-
- unused_blocks: [dynamic]rawptr,
- used_blocks: [dynamic]rawptr,
- out_band_allocations: [dynamic]rawptr,
-
- current_block: rawptr,
- current_pos: rawptr,
- bytes_left: int,
-
- block_allocator: Allocator,
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+small_stack_resize_non_zeroed :: proc(
+ s: ^Small_Stack,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := small_stack_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ return raw_data(bytes), err
}
+/*
+Resize an allocation without zero-initialization.
-DYNAMIC_POOL_BLOCK_SIZE_DEFAULT :: 65536
-DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT :: 6554
+This procedure resizes a memory region, specified by the `old_data` parameter
+to have a size `size` and alignment `alignment`. The newly allocated memory,
+if any is not explicitly zero-initialized.
+If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+If `size` is 0, this procedure acts just like `small_stack_free()`, freeing the
+memory region located at an address specified by `old_memory`.
-dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
- pool := (^Dynamic_Pool)(allocator_data)
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+small_stack_resize_bytes_non_zeroed :: proc(
+ s: ^Small_Stack,
+ old_data: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ if s.data == nil {
+ panic("Small stack is not initialized", loc)
+ }
+ old_memory := raw_data(old_data)
+ old_size := len(old_data)
+ alignment := alignment
+ alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2)
+ if old_memory == nil {
+ return small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ }
+ if size == 0 {
+ return nil, nil
+ }
+ start := uintptr(raw_data(s.data))
+ end := start + uintptr(len(s.data))
+ curr_addr := uintptr(old_memory)
+ if !(start <= curr_addr && curr_addr < end) {
+ // panic("Out of bounds memory address passed to stack allocator (resize)");
+ return nil, .Invalid_Pointer
+ }
+ if curr_addr >= start+uintptr(s.offset) {
+ // NOTE(bill): Treat as a double free
+ return nil, nil
+ }
+ if old_size == size {
+ return byte_slice(old_memory, size), nil
+ }
+ data, err := small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
+ if err == nil {
+ runtime.copy(data, byte_slice(old_memory, old_size))
+ }
+ return data, err
+
+}
+small_stack_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ s := cast(^Small_Stack)allocator_data
+ if s.data == nil {
+ return nil, .Invalid_Argument
+ }
switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- return dynamic_pool_alloc_bytes(pool, size)
+ case .Alloc:
+ return small_stack_alloc_bytes(s, size, alignment, loc)
+ case .Alloc_Non_Zeroed:
+ return small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc)
case .Free:
- return nil, .Mode_Not_Implemented
+ return nil, small_stack_free(s, old_memory, loc)
case .Free_All:
- dynamic_pool_free_all(pool)
- return nil, nil
- case .Resize, .Resize_Non_Zeroed:
- if old_size >= size {
- return byte_slice(old_memory, size), nil
- }
- data, err := dynamic_pool_alloc_bytes(pool, size)
- if err == nil {
- runtime.copy(data, byte_slice(old_memory, old_size))
- }
- return data, err
-
+ small_stack_free_all(s)
+ case .Resize:
+ return small_stack_resize_bytes(s, byte_slice(old_memory, old_size), size, alignment, loc)
+ case .Resize_Non_Zeroed:
+ return small_stack_resize_bytes_non_zeroed(s, byte_slice(old_memory, old_size), size, alignment, loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
- set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
+ set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
}
return nil, nil
-
case .Query_Info:
- info := (^Allocator_Query_Info)(old_memory)
- if info != nil && info.pointer != nil {
- info.size = pool.block_size
- info.alignment = pool.alignment
- return byte_slice(info, size_of(info^)), nil
- }
- return nil, nil
+ return nil, .Mode_Not_Implemented
}
return nil, nil
}
-@(require_results)
-dynamic_pool_allocator :: proc(pool: ^Dynamic_Pool) -> Allocator {
- return Allocator{
- procedure = dynamic_pool_allocator_proc,
- data = pool,
- }
+/* Preserved for compatibility */
+Dynamic_Pool :: Dynamic_Arena
+DYNAMIC_POOL_BLOCK_SIZE_DEFAULT :: DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT
+DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT :: DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT
+dynamic_pool_allocator_proc :: dynamic_arena_allocator_proc
+dynamic_pool_free_all :: dynamic_arena_free_all
+dynamic_pool_reset :: dynamic_arena_reset
+dynamic_pool_alloc_bytes :: dynamic_arena_alloc_bytes
+dynamic_pool_alloc :: dynamic_arena_alloc
+dynamic_pool_init :: dynamic_arena_init
+dynamic_pool_allocator :: dynamic_arena_allocator
+dynamic_pool_destroy :: dynamic_arena_destroy
+
+/*
+Default block size for dynamic arena.
+*/
+DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT :: 65536
+
+/*
+Default out-band size of the dynamic arena.
+*/
+DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT :: 6554
+
+/*
+Dynamic arena allocator data.
+*/
+Dynamic_Arena :: struct {
+ block_size: int,
+ out_band_size: int,
+ alignment: int,
+ unused_blocks: [dynamic]rawptr,
+ used_blocks: [dynamic]rawptr,
+ out_band_allocations: [dynamic]rawptr,
+ current_block: rawptr,
+ current_pos: rawptr,
+ bytes_left: int,
+ block_allocator: Allocator,
}
-dynamic_pool_init :: proc(pool: ^Dynamic_Pool,
- block_allocator := context.allocator,
- array_allocator := context.allocator,
- block_size := DYNAMIC_POOL_BLOCK_SIZE_DEFAULT,
- out_band_size := DYNAMIC_POOL_OUT_OF_BAND_SIZE_DEFAULT,
- alignment := 8) {
- pool.block_size = block_size
- pool.out_band_size = out_band_size
- pool.alignment = alignment
+/*
+Initialize a dynamic arena.
+
+This procedure initializes a dynamic arena. The specified `block_allocator`
+will be used to allocate arena blocks, and `array_allocator` to allocate
+arrays of blocks and out-band blocks. The blocks have the default size of
+`block_size` and out-band threshold will be `out_band_size`. All allocations
+will be aligned to a boundary specified by `alignment`.
+*/
+dynamic_arena_init :: proc(
+ pool: ^Dynamic_Arena,
+ block_allocator := context.allocator,
+ array_allocator := context.allocator,
+ block_size := DYNAMIC_ARENA_BLOCK_SIZE_DEFAULT,
+ out_band_size := DYNAMIC_ARENA_OUT_OF_BAND_SIZE_DEFAULT,
+ alignment := DEFAULT_ALIGNMENT,
+) {
+ pool.block_size = block_size
+ pool.out_band_size = out_band_size
+ pool.alignment = alignment
pool.block_allocator = block_allocator
pool.out_band_allocations.allocator = array_allocator
- pool. unused_blocks.allocator = array_allocator
- pool. used_blocks.allocator = array_allocator
+ pool.unused_blocks.allocator = array_allocator
+ pool.used_blocks.allocator = array_allocator
}
-dynamic_pool_destroy :: proc(pool: ^Dynamic_Pool) {
- dynamic_pool_free_all(pool)
- delete(pool.unused_blocks)
- delete(pool.used_blocks)
- delete(pool.out_band_allocations)
+/*
+Dynamic arena allocator.
- zero(pool, size_of(pool^))
-}
+The dynamic arena allocator uses blocks of a specific size, allocated on-demand
+using the block allocator. This allocator acts similarly to arena. All
+allocations in a block happen contiguously, from start to end. If an allocation
+does not fit into the remaining space of the block, and its size is smaller
+than the specified out-band size, a new block is allocated using the
+`block_allocator` and the allocation is performed from a newly-allocated block.
+If an allocation has bigger size than the specified out-band size, a new block
+is allocated such that the allocation fits into this new block. This is referred
+to as an *out-band allocation*. The out-band blocks are kept separately from
+normal blocks.
+Just like arena, the dynamic arena does not support freeing of individual
+objects.
+*/
@(require_results)
-dynamic_pool_alloc :: proc(pool: ^Dynamic_Pool, bytes: int) -> (rawptr, Allocator_Error) {
- data, err := dynamic_pool_alloc_bytes(pool, bytes)
+dynamic_arena_allocator :: proc(a: ^Dynamic_Arena) -> Allocator {
+ return Allocator{
+ procedure = dynamic_arena_allocator_proc,
+ data = a,
+ }
+}
+
+/*
+Destroy a dynamic arena.
+
+This procedure frees all allocations, made on a dynamic arena, including the
+unused blocks, as well as the arrays for storing blocks.
+*/
+dynamic_arena_destroy :: proc(a: ^Dynamic_Arena) {
+ dynamic_arena_free_all(a)
+ delete(a.unused_blocks)
+ delete(a.used_blocks)
+ delete(a.out_band_allocations)
+ zero(a, size_of(a^))
+}
+
+@(private="file")
+_dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, loc := #caller_location) -> (err: Allocator_Error) {
+ if a.block_allocator.procedure == nil {
+ panic("You must call arena_init on a Pool before using it", loc)
+ }
+ if a.current_block != nil {
+ append(&a.used_blocks, a.current_block, loc=loc)
+ }
+ new_block: rawptr
+ if len(a.unused_blocks) > 0 {
+ new_block = pop(&a.unused_blocks)
+ } else {
+ data: []byte
+ data, err = a.block_allocator.procedure(
+ a.block_allocator.data,
+ Allocator_Mode.Alloc,
+ a.block_size,
+ a.alignment,
+ nil,
+ 0,
+ )
+ new_block = raw_data(data)
+ }
+ a.bytes_left = a.block_size
+ a.current_pos = new_block
+ a.current_block = new_block
+ return
+}
+
+/*
+Allocate memory from a dynamic arena.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from a dynamic arena `a`. The allocated memory is
+zero-initialized. This procedure returns a pointer to the newly allocated memory
+region.
+*/
+@(private, require_results)
+dynamic_arena_alloc :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) {
+ data, err := dynamic_arena_alloc_bytes(a, size, loc)
return raw_data(data), err
}
+/*
+Allocate memory from a dynamic arena.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from a dynamic arena `a`. The allocated memory is
+zero-initialized. This procedure returns a slice of the newly allocated memory
+region.
+*/
@(require_results)
-dynamic_pool_alloc_bytes :: proc(p: ^Dynamic_Pool, bytes: int) -> ([]byte, Allocator_Error) {
- cycle_new_block :: proc(p: ^Dynamic_Pool) -> (err: Allocator_Error) {
- if p.block_allocator.procedure == nil {
- panic("You must call pool_init on a Pool before using it")
- }
+dynamic_arena_alloc_bytes :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
+ bytes, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
- if p.current_block != nil {
- append(&p.used_blocks, p.current_block)
- }
+/*
+Allocate non-initialized memory from a dynamic arena.
- new_block: rawptr
- if len(p.unused_blocks) > 0 {
- new_block = pop(&p.unused_blocks)
- } else {
- data: []byte
- data, err = p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
- p.block_size, p.alignment,
- nil, 0)
- new_block = raw_data(data)
- }
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from a dynamic arena `a`. The allocated memory is not explicitly
+zero-initialized. This procedure returns a pointer to the newly allocated
+memory region.
+*/
+@(require_results)
+dynamic_arena_alloc_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) {
+ data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
+ return raw_data(data), err
+}
- p.bytes_left = p.block_size
- p.current_pos = new_block
- p.current_block = new_block
- return
- }
+/*
+Allocate non-initialized memory from a dynamic arena.
- n := align_formula(bytes, p.alignment)
- if n > p.block_size {
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment` from a dynamic arena `a`. The allocated memory is not explicitly
+zero-initialized. This procedure returns a slice of the newly allocated
+memory region.
+*/
+@(require_results)
+dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
+ n := align_formula(size, a.alignment)
+ if n > a.block_size {
return nil, .Invalid_Argument
}
- if n >= p.out_band_size {
- assert(p.block_allocator.procedure != nil)
- memory, err := p.block_allocator.procedure(p.block_allocator.data, Allocator_Mode.Alloc,
- p.block_size, p.alignment,
- nil, 0)
+ if n >= a.out_band_size {
+ assert(a.block_allocator.procedure != nil, "Backing block allocator must be initialized", loc=loc)
+ memory, err := alloc_bytes_non_zeroed(a.block_size, a.alignment, a.block_allocator, loc)
if memory != nil {
- append(&p.out_band_allocations, raw_data(memory))
+ append(&a.out_band_allocations, raw_data(memory), loc = loc)
}
return memory, err
}
-
- if p.bytes_left < n {
- err := cycle_new_block(p)
+ if a.bytes_left < n {
+ err := _dynamic_arena_cycle_new_block(a, loc)
if err != nil {
return nil, err
}
- if p.current_block == nil {
+ if a.current_block == nil {
return nil, .Out_Of_Memory
}
}
-
- memory := p.current_pos
- p.current_pos = ([^]byte)(p.current_pos)[n:]
- p.bytes_left -= n
- return ([^]byte)(memory)[:bytes], nil
+ memory := a.current_pos
+ a.current_pos = ([^]byte)(a.current_pos)[n:]
+ a.bytes_left -= n
+ return ([^]byte)(memory)[:size], nil
}
+/*
+Reset the dynamic arena.
-dynamic_pool_reset :: proc(p: ^Dynamic_Pool) {
- if p.current_block != nil {
- append(&p.unused_blocks, p.current_block)
- p.current_block = nil
+This procedure frees all the allocations, owned by the dynamic arena, excluding
+the unused blocks.
+*/
+dynamic_arena_reset :: proc(a: ^Dynamic_Arena, loc := #caller_location) {
+ if a.current_block != nil {
+ append(&a.unused_blocks, a.current_block, loc=loc)
+ a.current_block = nil
}
-
- for block in p.used_blocks {
- append(&p.unused_blocks, block)
+ for block in a.used_blocks {
+ append(&a.unused_blocks, block, loc=loc)
}
- clear(&p.used_blocks)
+ clear(&a.used_blocks)
+ for allocation in a.out_band_allocations {
+ free(allocation, a.block_allocator, loc=loc)
+ }
+ clear(&a.out_band_allocations)
+ a.bytes_left = 0 // Make new allocations call `_dynamic_arena_cycle_new_block` again.
+}
+
+/*
+Free all memory from a dynamic arena.
- for a in p.out_band_allocations {
- free(a, p.block_allocator)
+This procedure frees all the allocations, owned by the dynamic arena, including
+the unused blocks.
+*/
+dynamic_arena_free_all :: proc(a: ^Dynamic_Arena, loc := #caller_location) {
+ dynamic_arena_reset(a)
+ for block in a.unused_blocks {
+ free(block, a.block_allocator, loc)
}
- clear(&p.out_band_allocations)
+ clear(&a.unused_blocks)
+}
+
+/*
+Resize an allocation.
+
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is zero-initialized.
- p.bytes_left = 0 // Make new allocations call `cycle_new_block` again.
+If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing
+the memory region located at an address specified by `old_memory`.
+
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+dynamic_arena_resize :: proc(
+ a: ^Dynamic_Arena,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := dynamic_arena_resize_bytes(a, byte_slice(old_memory, old_size), size, loc)
+ return raw_data(bytes), err
}
-dynamic_pool_free_all :: proc(p: ^Dynamic_Pool) {
- dynamic_pool_reset(p)
+/*
+Resize an allocation.
+
+This procedure resizes a memory region, specified by `old_data`, to have a size
+`size` and alignment `alignment`. The newly allocated memory, if any is
+zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
- for block in p.unused_blocks {
- free(block, p.block_allocator)
+If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+dynamic_arena_resize_bytes :: proc(
+ a: ^Dynamic_Arena,
+ old_data: []byte,
+ size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, old_data, size, loc)
+ if bytes != nil {
+ if old_data == nil {
+ zero_slice(bytes)
+ } else if size > len(old_data) {
+ zero_slice(bytes[len(old_data):])
+ }
}
- clear(&p.unused_blocks)
+ return bytes, err
}
+/*
+Resize an allocation without zero-initialization.
-panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int,loc := #caller_location) -> ([]byte, Allocator_Error) {
+This procedure resizes a memory region, defined by its location, `old_memory`,
+and its size, `old_size` to have a size `size` and alignment `alignment`. The
+newly allocated memory, if any is not explicitly zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing the
+memory region located at an address specified by `old_memory`.
+
+This procedure returns the pointer to the resized memory region.
+*/
+@(require_results)
+dynamic_arena_resize_non_zeroed :: proc(
+ a: ^Dynamic_Arena,
+ old_memory: rawptr,
+ old_size: int,
+ size: int,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, byte_slice(old_memory, old_size), size, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Resize an allocation.
+This procedure resizes a memory region, specified by `old_data`, to have a size
+`size` and alignment `alignment`. The newly allocated memory, if any is not
+explicitly zero-initialized.
+
+If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`,
+allocating a memory region `size` bytes in size, aligned on a boundary specified
+by `alignment`.
+
+If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing
+the memory region located at an address specified by `old_memory`.
+
+This procedure returns the slice of the resized memory region.
+*/
+@(require_results)
+dynamic_arena_resize_bytes_non_zeroed :: proc(
+ a: ^Dynamic_Arena,
+ old_data: []byte,
+ size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ old_memory := raw_data(old_data)
+ old_size := len(old_data)
+ if old_size >= size {
+ return byte_slice(old_memory, size), nil
+ }
+ data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc)
+ if err == nil {
+ runtime.copy(data, byte_slice(old_memory, old_size))
+ }
+ return data, err
+}
+
+dynamic_arena_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size: int,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ arena := (^Dynamic_Arena)(allocator_data)
switch mode {
case .Alloc:
- if size > 0 {
- panic("mem: panic allocator, .Alloc called", loc=loc)
- }
+ return dynamic_arena_alloc_bytes(arena, size, loc)
case .Alloc_Non_Zeroed:
- if size > 0 {
- panic("mem: panic allocator, .Alloc_Non_Zeroed called", loc=loc)
- }
- case .Resize:
- if size > 0 {
- panic("mem: panic allocator, .Resize called", loc=loc)
- }
- case .Resize_Non_Zeroed:
- if size > 0 {
- panic("mem: panic allocator, .Resize_Non_Zeroed called", loc=loc)
- }
+ return dynamic_arena_alloc_bytes_non_zeroed(arena, size, loc)
case .Free:
- if old_memory != nil {
- panic("mem: panic allocator, .Free called", loc=loc)
- }
+ return nil, .Mode_Not_Implemented
case .Free_All:
- panic("mem: panic allocator, .Free_All called", loc=loc)
-
+ dynamic_arena_free_all(arena, loc)
+ case .Resize:
+ return dynamic_arena_resize_bytes(arena, byte_slice(old_memory, old_size), size, loc)
+ case .Resize_Non_Zeroed:
+ return dynamic_arena_resize_bytes_non_zeroed(arena, byte_slice(old_memory, old_size), size, loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
- set^ = {.Query_Features}
+ set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
}
return nil, nil
-
case .Query_Info:
- panic("mem: panic allocator, .Query_Info called", loc=loc)
+ info := (^Allocator_Query_Info)(old_memory)
+ if info != nil && info.pointer != nil {
+ info.size = arena.block_size
+ info.alignment = arena.alignment
+ return byte_slice(info, size_of(info^)), nil
+ }
+ return nil, nil
}
-
return nil, nil
}
-@(require_results)
-panic_allocator :: proc() -> Allocator {
- return Allocator{
- procedure = panic_allocator_proc,
- data = nil,
- }
-}
-
-
-
-
-
+/*
+Header of the buddy block.
+*/
Buddy_Block :: struct #align(align_of(uint)) {
size: uint,
is_free: bool,
}
+/*
+Obtain the next buddy block.
+*/
@(require_results)
buddy_block_next :: proc(block: ^Buddy_Block) -> ^Buddy_Block {
return (^Buddy_Block)(([^]byte)(block)[block.size:])
}
+/*
+Split the block into two, by truncating the given block to a given size.
+*/
@(require_results)
buddy_block_split :: proc(block: ^Buddy_Block, size: uint) -> ^Buddy_Block {
block := block
@@ -894,12 +1971,14 @@ buddy_block_split :: proc(block: ^Buddy_Block, size: uint) -> ^Buddy_Block {
return nil
}
+/*
+Coalesce contiguous blocks in a range of blocks into one.
+*/
buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) {
for {
// Keep looping until there are no more buddies to coalesce
block := head
buddy := buddy_block_next(block)
-
no_coalescence := true
for block < tail && buddy < tail { // make sure the buddies are within the range
if block.is_free && buddy.is_free && block.size == buddy.size {
@@ -922,28 +2001,26 @@ buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) {
}
}
}
-
if no_coalescence {
return
}
}
}
-
+/*
+Find the best block for storing a given size in a range of blocks.
+*/
@(require_results)
buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Block {
assert(size != 0)
-
best_block: ^Buddy_Block
block := head // left
buddy := buddy_block_next(block) // right
-
// The entire memory section between head and tail is free,
// just call 'buddy_block_split' to get the allocation
if buddy == tail && block.is_free {
return buddy_block_split(block, size)
}
-
// Find the block which is the 'best_block' to requested allocation sized
for block < tail && buddy < tail { // make sure the buddies are within the range
// If both buddies are free, coalesce them together
@@ -954,7 +2031,6 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
if size <= block.size && (best_block == nil || block.size <= best_block.size) {
best_block = block
}
-
block = buddy_block_next(buddy)
if block < tail {
// Delay the buddy block for the next iteration
@@ -962,20 +2038,16 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
}
continue
}
-
-
if block.is_free && size <= block.size &&
(best_block == nil || block.size <= best_block.size) {
best_block = block
}
-
if buddy.is_free && size <= buddy.size &&
(best_block == nil || buddy.size < best_block.size) {
// If each buddy are the same size, then it makes more sense
// to pick the buddy as it "bounces around" less
best_block = buddy
}
-
if (block.size <= buddy.size) {
block = buddy_block_next(buddy)
if (block < tail) {
@@ -988,23 +2060,33 @@ buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Bl
buddy = buddy_block_next(buddy)
}
}
-
if best_block != nil {
// This will handle the case if the 'best_block' is also the perfect fit
return buddy_block_split(best_block, size)
}
-
// Maybe out of memory
return nil
}
-
+/*
+The buddy allocator data.
+*/
Buddy_Allocator :: struct {
head: ^Buddy_Block,
tail: ^Buddy_Block,
alignment: uint,
}
+/*
+Buddy allocator.
+
+The buddy allocator is a type of allocator that splits the backing buffer into
+multiple regions called buddy blocks. Initially, the allocator only has one
+block with the size of the backing buffer. Upon each allocation, the allocator
+finds the smallest block that can fit the size of requested memory region, and
+splits the block according to the allocation size. If no block can be found,
+the contiguous free blocks are coalesced and the search is performed again.
+*/
@(require_results)
buddy_allocator :: proc(b: ^Buddy_Allocator) -> Allocator {
return Allocator{
@@ -1013,48 +2095,97 @@ buddy_allocator :: proc(b: ^Buddy_Allocator) -> Allocator {
}
}
-buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint) {
- assert(data != nil)
- assert(is_power_of_two(uintptr(len(data))))
- assert(is_power_of_two(uintptr(alignment)))
+/*
+Initialize the buddy allocator.
+This procedure initializes the buddy allocator `b` with a backing buffer `data`
+and block alignment specified by `alignment`.
+*/
+buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint, loc := #caller_location) {
+ assert(data != nil)
+ assert(is_power_of_two(uintptr(len(data))), "Size of the backing buffer must be power of two", loc)
+ assert(is_power_of_two(uintptr(alignment)), "Alignment must be a power of two", loc)
alignment := alignment
if alignment < size_of(Buddy_Block) {
alignment = size_of(Buddy_Block)
}
-
ptr := raw_data(data)
- assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment")
-
+ assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment", loc)
b.head = (^Buddy_Block)(ptr)
-
b.head.size = len(data)
b.head.is_free = true
-
b.tail = buddy_block_next(b.head)
-
b.alignment = alignment
}
+/*
+Get required block size to fit in the allocation as well as the alignment padding.
+*/
@(require_results)
buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint {
size := size
actual_size := b.alignment
size += size_of(Buddy_Block)
size = align_forward_uint(size, b.alignment)
-
for size > actual_size {
actual_size <<= 1
}
-
return actual_size
}
+/*
+Allocate memory from a buddy allocator.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is zero-initialized. This procedure
+returns a pointer to the allocated memory region.
+*/
@(require_results)
-buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint, zeroed: bool) -> ([]byte, Allocator_Error) {
+buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint) -> (rawptr, Allocator_Error) {
+ bytes, err := buddy_allocator_alloc_bytes(b, size)
+ return raw_data(bytes), err
+}
+
+/*
+Allocate memory from a buddy allocator.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is zero-initialized. This procedure
+returns a slice of the allocated memory region.
+*/
+@(require_results)
+buddy_allocator_alloc_bytes :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) {
+ bytes, err := buddy_allocator_alloc_bytes_non_zeroed(b, size)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
+
+/*
+Allocate non-initialized memory from a buddy allocator.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is not explicitly zero-initialized.
+This procedure returns a pointer to the allocated memory region.
+*/
+@(require_results)
+buddy_allocator_alloc_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> (rawptr, Allocator_Error) {
+ bytes, err := buddy_allocator_alloc_bytes_non_zeroed(b, size)
+ return raw_data(bytes), err
+}
+
+/*
+Allocate non-initialized memory from a buddy allocator.
+
+This procedure allocates `size` bytes of memory aligned on a boundary specified
+by `alignment`. The allocated memory region is not explicitly zero-initialized.
+This procedure returns a slice of the allocated memory region.
+*/
+@(require_results)
+buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) {
if size != 0 {
actual_size := buddy_block_size_required(b, size)
-
found := buddy_block_find_best(b.head, b.tail, actual_size)
if found != nil {
// Try to coalesce all the free buddy blocks and then search again
@@ -1065,60 +2196,71 @@ buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint, zeroed: bool) ->
return nil, .Out_Of_Memory
}
found.is_free = false
-
data := ([^]byte)(found)[b.alignment:][:size]
- if zeroed {
- zero_slice(data)
- }
return data, nil
}
return nil, nil
}
+/*
+Free memory to the buddy allocator.
+
+This procedure frees the memory region allocated at pointer `ptr`.
+
+If `ptr` is not the latest allocation and is not a leaked allocation, this
+operation is a no-op.
+*/
buddy_allocator_free :: proc(b: ^Buddy_Allocator, ptr: rawptr) -> Allocator_Error {
if ptr != nil {
if !(b.head <= ptr && ptr <= b.tail) {
return .Invalid_Pointer
}
-
block := (^Buddy_Block)(([^]byte)(ptr)[-b.alignment:])
block.is_free = true
-
buddy_block_coalescence(b.head, b.tail)
}
return nil
}
-buddy_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int,loc := #caller_location) -> ([]byte, Allocator_Error) {
+/*
+Free all memory to the buddy allocator.
+*/
+buddy_allocator_free_all :: proc(b: ^Buddy_Allocator) {
+ alignment := b.alignment
+ head := ([^]byte)(b.head)
+ tail := ([^]byte)(b.tail)
+ data := head[:ptr_sub(tail, head)]
+ buddy_allocator_init(b, data, alignment)
+}
+buddy_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
b := (^Buddy_Allocator)(allocator_data)
-
switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- return buddy_allocator_alloc(b, uint(size), mode == .Alloc)
+ case .Alloc:
+ return buddy_allocator_alloc_bytes(b, uint(size))
+ case .Alloc_Non_Zeroed:
+ return buddy_allocator_alloc_bytes_non_zeroed(b, uint(size))
case .Resize:
- return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, buddy_allocator(b))
+ return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, buddy_allocator(b), loc)
case .Resize_Non_Zeroed:
- return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, buddy_allocator(b))
+ return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, buddy_allocator(b), loc)
case .Free:
return nil, buddy_allocator_free(b, old_memory)
case .Free_All:
-
- alignment := b.alignment
- head := ([^]byte)(b.head)
- tail := ([^]byte)(b.tail)
- data := head[:ptr_sub(tail, head)]
- buddy_allocator_init(b, data, alignment)
-
+ buddy_allocator_free_all(b)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Query_Features, .Alloc, .Alloc_Non_Zeroed, .Resize, .Resize_Non_Zeroed, .Free, .Free_All, .Query_Info}
}
return nil, nil
-
case .Query_Info:
info := (^Allocator_Query_Info)(old_memory)
if info != nil && info.pointer != nil {
@@ -1126,7 +2268,6 @@ buddy_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
if !(b.head <= ptr && ptr <= b.tail) {
return nil, .Invalid_Pointer
}
-
block := (^Buddy_Block)(([^]byte)(ptr)[-b.alignment:])
info.size = int(block.size)
info.alignment = int(b.alignment)
@@ -1134,6 +2275,83 @@ buddy_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
}
return nil, nil
}
-
return nil, nil
}
+
+// An allocator that keeps track of allocation sizes and passes it along to resizes.
+// This is useful if you are using a library that needs an equivalent of `realloc` but want to use
+// the Odin allocator interface.
+//
+// You want to wrap your allocator into this one if you are trying to use any allocator that relies
+// on the old size to work.
+//
+// The overhead of this allocator is an extra max(alignment, size_of(Header)) bytes allocated for each allocation, these bytes are
+// used to store the size and original pointer.
+Compat_Allocator :: struct {
+ parent: Allocator,
+}
+
+compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.allocator) {
+ rra.parent = allocator
+}
+
+compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
+ return Allocator{
+ data = rra,
+ procedure = compat_allocator_proc,
+ }
+}
+
+compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr, old_size: int,
+ location := #caller_location) -> (data: []byte, err: Allocator_Error) {
+ size, old_size := size, old_size
+
+ Header :: struct {
+ size: int,
+ ptr: rawptr,
+ }
+
+ rra := (^Compat_Allocator)(allocator_data)
+ switch mode {
+ case .Alloc, .Alloc_Non_Zeroed:
+ a := max(alignment, size_of(Header))
+ size += a
+ assert(size >= 0, "overflow")
+
+ allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) or_return
+ #no_bounds_check data = allocation[a:]
+
+ ([^]Header)(raw_data(data))[-1] = {
+ size = size,
+ ptr = raw_data(allocation),
+ }
+ return
+
+ case .Free:
+ header := ([^]Header)(old_memory)[-1]
+ return rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location)
+
+ case .Resize, .Resize_Non_Zeroed:
+ header := ([^]Header)(old_memory)[-1]
+
+ a := max(alignment, size_of(header))
+ size += a
+ assert(size >= 0, "overflow")
+
+ allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) or_return
+ #no_bounds_check data = allocation[a:]
+
+ ([^]Header)(raw_data(data))[-1] = {
+ size = size,
+ ptr = raw_data(allocation),
+ }
+ return
+
+ case .Free_All, .Query_Info, .Query_Features:
+ return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location)
+
+ case: unreachable()
+ }
+}
diff --git a/core/mem/doc.odin b/core/mem/doc.odin
index 44c93f798..98755d797 100644
--- a/core/mem/doc.odin
+++ b/core/mem/doc.odin
@@ -1,34 +1,114 @@
/*
-package mem implements various types of allocators.
+The `mem` package implements various allocators and provides utility procedures
+for dealing with memory, pointers and slices.
+The documentation below describes basic concepts, applicable to the `mem`
+package.
-An example of how to use the `Tracking_Allocator` to track subsequent allocations
-in your program and report leaks and bad frees:
+## Pointers, multipointers, and slices
-Example:
- package foo
+A *pointer* is an abstraction of an *address*, a numberic value representing the
+location of an object in memory. That object is said to be *pointed to* by the
+pointer. To obtain the address of a pointer, cast it to `uintptr`.
- import "core:mem"
- import "core:fmt"
+A multipointer is a pointer that points to multiple objects. Unlike a pointer,
+a multipointer can be indexed, but does not have a definite length. A slice is
+a pointer that points to multiple objects equipped with the length, specifying
+the amount of objects a slice points to.
- _main :: proc() {
- // do stuff
- }
+When object's values are read through a pointer, that operation is called a
+*load* operation. When memory is read through a pointer, that operation is
+called a *store* operation. Both of these operations can be called a *memory
+access operation*.
- main :: proc() {
- track: mem.Tracking_Allocator
- mem.tracking_allocator_init(&track, context.allocator)
- defer mem.tracking_allocator_destroy(&track)
- context.allocator = mem.tracking_allocator(&track)
+## Allocators
- _main()
+In C and C++ memory models, allocations of objects in memory are typically
+treated individually with a generic allocator (The `malloc` procedure). Which in
+some scenarios can lead to poor cache utilization, slowdowns on individual
+objects' memory management and growing complexity of the code needing to keep
+track of the pointers and their lifetimes.
- for _, leak in track.allocation_map {
- fmt.printf("%v leaked %m\n", leak.location, leak.size)
- }
- for bad_free in track.bad_free_array {
- fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
- }
- }
+Using different kinds of *allocators* for different purposes can solve these
+problems. The allocators are typically optimized for specific use-cases and
+can potentially simplify the memory management code.
+
+For example, in the context of making a game, having an Arena allocator could
+simplify allocations of any temporary memory, because the programmer doesn't
+have to keep track of which objects need to be freed every time they are
+allocated, because at the end of every frame the whole allocator is reset to
+its initial state and all objects are freed at once.
+
+The allocators have different kinds of restrictions on object lifetimes, sizes,
+alignment and can be a significant gain, if used properly. Odin supports
+allocators on a language level.
+
+Operations such as `new`, `free` and `delete` by default will use
+`context.allocator`, which can be overridden by the user. When an override
+happens all called procedures will inherit the new context and use the same
+allocator.
+
+We will define one concept to simplify the description of some allocator-related
+procedures, which is ownership. If the memory was allocated via a specific
+allocator, that allocator is said to be the *owner* of that memory region. To
+note, unlike Rust, in Odin the memory ownership model is not strict.
+
+## Alignment
+
+An address is said to be *aligned to `N` bytes*, if the addresses's numeric
+value is divisible by `N`. The number `N` in this case can be referred to as
+the *alignment boundary*. Typically an alignment is a power of two integer
+value.
+
+A *natural alignment* of an object is typically equal to its size. For example
+a 16 bit integer has a natural alignment of 2 bytes. When an object is not
+located on its natural alignment boundary, accesses to that object are
+considered *unaligned*.
+
+Some machines issue a hardware **exception**, or experience **slowdowns** when a
+memory access operation occurs from an unaligned address. Examples of such
+operations are:
+
+- SIMD instructions on x86. These instructions require all memory accesses to be
+ on an address that is aligned to 16 bytes.
+- On ARM unaligned loads have an extra cycle penalty.
+
+As such, many operations that allocate memory in this package allow to
+explicitly specify the alignment of allocated pointers/slices. The default
+alignment for all operations is specified in a constant `mem.DEFAULT_ALIGNMENT`.
+
+## Zero by default
+
+Whenever new memory is allocated, via an allocator, or on the stack, by default
+Odin will zero-initialize that memory, even if it wasn't explicitly
+initialized. This allows for some convenience in certain scenarios and ease of
+debugging, which will not be described in detail here.
+
+However zero-initialization can be a cause of slowdowns, when allocating large
+buffers. For this reason, allocators have `*_non_zeroed` modes of allocation
+that allow the user to request for uninitialized memory and will avoid a
+relatively expensive zero-filling of the buffer.
+
+## Naming conventions
+
+The word `size` is used to denote the **size in bytes**. The word `length` is
+used to denote the count of objects.
+
+The allocation procedures use the following conventions:
+
+- If the name contains `alloc_bytes` or `resize_bytes`, then the procedure takes
+ in slice parameters and returns slices.
+- If the procedure name contains `alloc` or `resize`, then the procedure takes
+ in a raw pointer and returns raw pointers.
+- If the procedure name contains `free_bytes`, then the procedure takes in a
+ slice.
+- If the procedure name contains `free`, then the procedure takes in a pointer.
+
+Higher-level allocation procedures follow the following naming scheme:
+
+- `new`: Allocates a single object
+- `free`: Free a single object (opposite of `new`)
+- `make`: Allocate a group of objects
+- `delete`: Free a group of objects (opposite of `make`)
*/
package mem
diff --git a/core/mem/mem.odin b/core/mem/mem.odin
index d423cc1eb..67ed56c39 100644
--- a/core/mem/mem.odin
+++ b/core/mem/mem.odin
@@ -3,49 +3,185 @@ package mem
import "base:runtime"
import "base:intrinsics"
-Byte :: runtime.Byte
+/*
+The size, in bytes, of a single byte.
+
+This constant is equal to the value of `1`.
+*/
+Byte :: runtime.Byte
+
+/*
+The size, in bytes, of one kilobyte.
+
+This constant is equal to the amount of bytes in one kilobyte (also known as
+kibibyte), which is equal to 1024 bytes.
+*/
Kilobyte :: runtime.Kilobyte
+
+/*
+The size, in bytes, of one megabyte.
+
+This constant is equal to the amount of bytes in one megabyte (also known as
+mebibyte), which is equal to 1024 kilobyte.
+*/
Megabyte :: runtime.Megabyte
+
+/*
+The size, in bytes, of one gigabyte.
+
+This constant is equal to the amount of bytes in one gigabyte (also known as
+gibiibyte), which is equal to 1024 megabytes.
+*/
Gigabyte :: runtime.Gigabyte
+
+/*
+The size, in bytes, of one terabyte.
+
+This constant is equal to the amount of bytes in one terabyte (also known as
+tebiibyte), which is equal to 1024 gigabytes.
+*/
Terabyte :: runtime.Terabyte
+
+/*
+The size, in bytes, of one petabyte.
+
+This constant is equal to the amount of bytes in one petabyte (also known as
+pebiibyte), which is equal to 1024 terabytes.
+*/
Petabyte :: runtime.Petabyte
-Exabyte :: runtime.Exabyte
+/*
+The size, in bytes, of one exabyte.
+
+This constant is equal to the amount of bytes in one exabyte (also known as
+exbibyte), which is equal to 1024 petabytes.
+*/
+Exabyte :: runtime.Exabyte
+
+/*
+Set each byte of a memory range to a specific value.
+
+This procedure copies value specified by the `value` parameter into each of the
+`len` bytes of a memory range, located at address `data`.
+
+This procedure returns the pointer to `data`.
+*/
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
return runtime.memset(data, i32(value), len)
}
+
+/*
+Set each byte of a memory range to zero.
+
+This procedure copies the value `0` into the `len` bytes of a memory range,
+starting at address `data`.
+
+This procedure returns the pointer to `data`.
+*/
zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
intrinsics.mem_zero(data, len)
return data
}
+
+/*
+Set each byte of a memory range to zero.
+
+This procedure copies the value `0` into the `len` bytes of a memory range,
+starting at address `data`.
+
+This procedure returns the pointer to `data`.
+
+Unlike the `zero()` procedure, which can be optimized away or reordered by the
+compiler under certain circumstances, `zero_explicit()` procedure can not be
+optimized away or reordered with other memory access operations, and the
+compiler assumes volatile semantics of the memory.
+*/
zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr {
// This routine tries to avoid the compiler optimizing away the call,
- // so that it is always executed. It is intended to provided
+ // so that it is always executed. It is intended to provide
// equivalent semantics to those provided by the C11 Annex K 3.7.4.1
// memset_s call.
intrinsics.mem_zero_volatile(data, len) // Use the volatile mem_zero
intrinsics.atomic_thread_fence(.Seq_Cst) // Prevent reordering
return data
}
+
+/*
+Zero-fill the memory of an object.
+
+This procedure sets each byte of the object pointed to by the pointer `item`
+to zero, and returns the pointer to `item`.
+*/
zero_item :: proc "contextless" (item: $P/^$T) -> P {
intrinsics.mem_zero(item, size_of(T))
return item
}
+
+/*
+Zero-fill the memory of the slice.
+
+This procedure sets each byte of the slice pointed to by the slice `data`
+to zero, and returns the slice `data`.
+*/
zero_slice :: proc "contextless" (data: $T/[]$E) -> T {
zero(raw_data(data), size_of(E)*len(data))
return data
}
+/*
+Copy bytes from one memory range to another.
+This procedure copies `len` bytes of data, from the memory range pointed to by
+the `src` pointer into the memory range pointed to by the `dst` pointer, and
+returns the `dst` pointer.
+*/
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
intrinsics.mem_copy(dst, src, len)
return dst
}
+
+/*
+Copy bytes between two non-overlapping memory ranges.
+
+This procedure copies `len` bytes of data, from the memory range pointed to by
+the `src` pointer into the memory range pointed to by the `dst` pointer, and
+returns the `dst` pointer.
+
+This is a slightly more optimized version of the `copy` procedure that requires
+that memory ranges specified by the parameters to this procedure are not
+overlapping. If the memory ranges specified by `dst` and `src` pointers overlap,
+the behavior of this function may be unpredictable.
+*/
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
intrinsics.mem_copy_non_overlapping(dst, src, len)
return dst
}
+/*
+Compare two memory ranges defined by slices.
+
+This procedure performs a byte-by-byte comparison between memory ranges
+specified by slices `a` and `b`, and returns a value, specifying their relative
+ordering.
+
+If the return value is:
+- Equal to `-1`, then `a` is "smaller" than `b`.
+- Equal to `+1`, then `a` is "bigger" than `b`.
+- Equal to `0`, then `a` and `b` are equal.
+
+The comparison is performed as follows:
+1. Each byte, upto `min(len(a), len(b))` bytes is compared between `a` and `b`.
+ - If the byte in slice `a` is smaller than a byte in slice `b`, then comparison
+ stops and this procedure returns `-1`.
+ - If the byte in slice `a` is bigger than a byte in slice `b`, then comparison
+ stops and this procedure returns `+1`.
+ - Otherwise the comparison continues until `min(len(a), len(b))` are compared.
+2. If all the bytes in the range are equal, then the lengths of the slices are
+ compared.
+ - If the length of slice `a` is smaller than the length of slice `b`, then `-1` is returned.
+ - If the length of slice `b` is smaller than the length of slice `b`, then `+1` is returned.
+ - Otherwise `0` is returned.
+*/
@(require_results)
compare :: proc "contextless" (a, b: []byte) -> int {
res := compare_byte_ptrs(raw_data(a), raw_data(b), min(len(a), len(b)))
@@ -57,16 +193,89 @@ compare :: proc "contextless" (a, b: []byte) -> int {
return res
}
+/*
+Compare two memory ranges defined by byte pointers.
+
+This procedure performs a byte-by-byte comparison between memory ranges of size
+`n` located at addresses `a` and `b`, and returns a value, specifying their relative
+ordering.
+
+If the return value is:
+- Equal to `-1`, then `a` is "smaller" than `b`.
+- Equal to `+1`, then `a` is "bigger" than `b`.
+- Equal to `0`, then `a` and `b` are equal.
+
+The comparison is performed as follows:
+1. Each byte, upto `n` bytes is compared between `a` and `b`.
+ - If the byte in `a` is smaller than a byte in `b`, then comparison stops
+ and this procedure returns `-1`.
+ - If the byte in `a` is bigger than a byte in `b`, then comparison stops
+ and this procedure returns `+1`.
+ - Otherwise the comparison continues until `n` bytes are compared.
+2. If all the bytes in the range are equal, this procedure returns `0`.
+*/
@(require_results)
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
return runtime.memory_compare(a, b, n)
}
+/*
+Compare two memory ranges defined by pointers.
+
+This procedure performs a byte-by-byte comparison between memory ranges of size
+`n` located at addresses `a` and `b`, and returns a value, specifying their relative
+ordering.
+
+If the return value is:
+- Equal to `-1`, then `a` is "smaller" than `b`.
+- Equal to `+1`, then `a` is "bigger" than `b`.
+- Equal to `0`, then `a` and `b` are equal.
+
+The comparison is performed as follows:
+1. Each byte, upto `n` bytes is compared between `a` and `b`.
+ - If the byte in `a` is smaller than a byte in `b`, then comparison stops
+ and this procedure returns `-1`.
+ - If the byte in `a` is bigger than a byte in `b`, then comparison stops
+ and this procedure returns `+1`.
+ - Otherwise the comparison continues until `n` bytes are compared.
+2. If all the bytes in the range are equal, this procedure returns `0`.
+*/
+@(require_results)
+compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
+ return compare_byte_ptrs((^byte)(a), (^byte)(b), n)
+}
+
+/*
+Check whether two objects are equal on binary level.
+
+This procedure checks whether the memory ranges occupied by objects `a` and
+`b` are equal. See `compare_byte_ptrs()` for how this comparison is done.
+*/
+@(require_results)
+simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) {
+ a, b := a, b
+ return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0
+}
+
+/*
+Check if the memory range defined by a slice is zero-filled.
+
+This procedure checks whether every byte, pointed to by the slice, specified
+by the parameter `data`, is zero. If all bytes of the slice are zero, this
+procedure returns `true`. Otherwise this procedure returns `false`.
+*/
@(require_results)
check_zero :: proc(data: []byte) -> bool {
return check_zero_ptr(raw_data(data), len(data))
}
+/*
+Check if the memory range defined defined by a pointer is zero-filled.
+
+This procedure checks whether each of the `len` bytes, starting at address
+`ptr` is zero. If all bytes of this range are zero, this procedure returns
+`true`. Otherwise this procedure returns `false`.
+*/
@(require_results)
check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
switch {
@@ -81,57 +290,99 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool {
case 4: return intrinsics.unaligned_load((^u32)(ptr)) == 0
case 8: return intrinsics.unaligned_load((^u64)(ptr)) == 0
}
-
start := uintptr(ptr)
start_aligned := align_forward_uintptr(start, align_of(uintptr))
end := start + uintptr(len)
end_aligned := align_backward_uintptr(end, align_of(uintptr))
-
for b in start..<start_aligned {
if (^byte)(b)^ != 0 {
return false
}
}
-
for b := start_aligned; b < end_aligned; b += size_of(uintptr) {
if (^uintptr)(b)^ != 0 {
return false
}
}
-
for b in end_aligned..<end {
if (^byte)(b)^ != 0 {
return false
}
}
-
return true
}
-@(require_results)
-simple_equal :: proc "contextless" (a, b: $T) -> bool where intrinsics.type_is_simple_compare(T) {
- a, b := a, b
- return compare_byte_ptrs((^byte)(&a), (^byte)(&b), size_of(T)) == 0
-}
+/*
+Offset a given pointer by a given amount.
-@(require_results)
-compare_ptrs :: proc "contextless" (a, b: rawptr, n: int) -> int {
- return compare_byte_ptrs((^byte)(a), (^byte)(b), n)
-}
+This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
+of bytes specified by `offset*size_of(T)`, and returns the pointer `ptr`.
+**Note**: Prefer to use multipointer types, if possible.
+*/
ptr_offset :: intrinsics.ptr_offset
+
+/*
+Offset a given pointer by a given amount backwards.
+
+This procedure offsets the pointer `ptr` to an object of type `T`, by the amount
+of bytes specified by `offset*size_of(T)` in the negative direction, and
+returns the pointer `ptr`.
+*/
ptr_sub :: intrinsics.ptr_sub
+/*
+Construct a slice from pointer and length.
+
+This procedure creates a slice, that points to `len` amount of objects located
+at an address, specified by `ptr`.
+*/
@(require_results)
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
return ([^]T)(ptr)[:len]
}
+/*
+Construct a byte slice from raw pointer and length.
+
+This procedure creates a byte slice, that points to `len` amount of bytes
+located at an address specified by `data`.
+*/
@(require_results)
byte_slice :: #force_inline proc "contextless" (data: rawptr, #any_int len: int) -> []byte {
return ([^]u8)(data)[:max(len, 0)]
}
+/*
+Create a byte slice from pointer and length.
+
+This procedure creates a byte slice, pointing to `len` objects, starting from
+the address specified by `ptr`.
+*/
+@(require_results)
+ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
+ return transmute([]byte)Raw_Slice{ptr, len*size_of(T)}
+}
+
+/*
+Obtain the slice, pointing to the contents of `any`.
+
+This procedure returns the slice, pointing to the contents of the specified
+value of the `any` type.
+*/
+@(require_results)
+any_to_bytes :: proc "contextless" (val: any) -> []byte {
+ ti := type_info_of(val.id)
+ size := ti != nil ? ti.size : 0
+ return transmute([]byte)Raw_Slice{val.data, size}
+}
+
+/*
+Obtain a byte slice from any slice.
+
+This procedure returns a slice, that points to the same bytes as the slice,
+specified by `slice` and returns the resulting byte slice.
+*/
@(require_results)
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
s := transmute(Raw_Slice)slice
@@ -139,6 +390,15 @@ slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
return transmute([]byte)s
}
+/*
+Transmute slice to a different type.
+
+This procedure performs an operation similar to transmute, returning a slice of
+type `T` that points to the same bytes as the slice specified by `slice`
+parameter. Unlike plain transmute operation, this procedure adjusts the length
+of the resulting slice, such that the resulting slice points to the correct
+amount of objects to cover the memory region pointed to by `slice`.
+*/
@(require_results)
slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
when size_of(A) == 0 || size_of(B) == 0 {
@@ -150,12 +410,25 @@ slice_data_cast :: proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -> T {
}
}
+/*
+Obtain data and length of a slice.
+
+This procedure returns the pointer to the start of the memory region pointed to
+by slice `slice` and the length of the slice.
+*/
@(require_results)
slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) {
s := transmute(Raw_Slice)slice
return (^T)(s.data), s.len
}
+/*
+Create a dynamic array from slice.
+
+This procedure creates a dynamic array, using slice `backing` as the backing
+buffer for the dynamic array. The resulting dynamic array can not grow beyond
+the size of the specified slice.
+*/
@(require_results)
buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
return transmute([dynamic]E)Raw_Dynamic_Array{
@@ -169,19 +442,12 @@ buffer_from_slice :: proc "contextless" (backing: $T/[]$E) -> [dynamic]E {
}
}
-@(require_results)
-ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
- return transmute([]byte)Raw_Slice{ptr, len*size_of(T)}
-}
-
-@(require_results)
-any_to_bytes :: proc "contextless" (val: any) -> []byte {
- ti := type_info_of(val.id)
- size := ti != nil ? ti.size : 0
- return transmute([]byte)Raw_Slice{val.data, size}
-}
-
+/*
+Check whether a number is a power of two.
+This procedure checks whether a given pointer-sized unsigned integer contains
+a power-of-two value.
+*/
@(require_results)
is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
if x <= 0 {
@@ -190,66 +456,167 @@ is_power_of_two :: proc "contextless" (x: uintptr) -> bool {
return (x & (x-1)) == 0
}
-@(require_results)
-align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
- return rawptr(align_forward_uintptr(uintptr(ptr), align))
+/*
+Check if a pointer is aligned.
+
+This procedure checks whether a pointer `x` is aligned to a boundary specified
+by `align`, and returns `true` if the pointer is aligned, and false otherwise.
+*/
+is_aligned :: proc "contextless" (x: rawptr, align: int) -> bool {
+ p := uintptr(x)
+ return (p & (1<<uintptr(align) - 1)) == 0
}
+/*
+Align uintptr forward.
+
+This procedure returns the next address after `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
assert(is_power_of_two(align))
+ return (ptr + align-1) & ~(align-1)
+}
- p := ptr
- modulo := p & (align-1)
- if modulo != 0 {
- p += align - modulo
- }
- return p
+/*
+Align pointer forward.
+
+This procedure returns the next address after `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
+@(require_results)
+align_forward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
+ return rawptr(align_forward_uintptr(uintptr(ptr), align))
}
+/*
+Align int forward.
+
+This procedure returns the next address after `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
align_forward_int :: proc(ptr, align: int) -> int {
return int(align_forward_uintptr(uintptr(ptr), uintptr(align)))
}
+
+/*
+Align uint forward.
+
+This procedure returns the next address after `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
align_forward_uint :: proc(ptr, align: uint) -> uint {
return uint(align_forward_uintptr(uintptr(ptr), uintptr(align)))
}
+/*
+Align uintptr backwards.
+
+This procedure returns the previous address before `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
-align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
- return rawptr(align_backward_uintptr(uintptr(ptr), align))
+align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
+ assert(is_power_of_two(align))
+ return ptr & ~(align-1)
}
+/*
+Align rawptr backwards.
+
+This procedure returns the previous address before `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
-align_backward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
- return align_forward_uintptr(ptr - align + 1, align)
+align_backward :: proc(ptr: rawptr, align: uintptr) -> rawptr {
+ return rawptr(align_backward_uintptr(uintptr(ptr), align))
}
+/*
+Align int backwards.
+
+This procedure returns the previous address before `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
align_backward_int :: proc(ptr, align: int) -> int {
return int(align_backward_uintptr(uintptr(ptr), uintptr(align)))
}
+
+/*
+Align uint backwards.
+
+This procedure returns the previous address before `ptr`, that is located on the
+alignment boundary specified by `align`. If `ptr` is already aligned to `align`
+bytes, `ptr` is returned.
+
+The specified alignment must be a power of 2.
+*/
@(require_results)
align_backward_uint :: proc(ptr, align: uint) -> uint {
return uint(align_backward_uintptr(uintptr(ptr), uintptr(align)))
}
+/*
+Create a context with a given allocator.
+
+This procedure returns a copy of the current context with the allocator replaced
+by the allocator `a`.
+*/
@(require_results)
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
context.allocator = a
return context
}
+/*
+Copy the value from a pointer into a value.
+
+This procedure copies the object of type `T` pointed to by the pointer `ptr`
+into a new stack-allocated value and returns that value.
+*/
@(require_results)
reinterpret_copy :: proc "contextless" ($T: typeid, ptr: rawptr) -> (value: T) {
copy(&value, ptr, size_of(T))
return
}
+/*
+Dynamic array with a fixed capacity buffer.
+This type represents dynamic arrays with a fixed-size backing buffer. Upon
+allocating memory beyond reaching the maximum capacity, allocations from fixed
+byte buffers return `nil` and no error.
+*/
Fixed_Byte_Buffer :: distinct [dynamic]byte
+/*
+Create a fixed byte buffer from a slice.
+*/
@(require_results)
make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buffer {
s := transmute(Raw_Slice)backing
@@ -264,40 +631,60 @@ make_fixed_byte_buffer :: proc "contextless" (backing: []byte) -> Fixed_Byte_Buf
return transmute(Fixed_Byte_Buffer)d
}
+/*
+General-purpose align formula.
-
+This procedure is equivalent to `align_forward`, but it does not require the
+alignment to be a power of two.
+*/
@(require_results)
align_formula :: proc "contextless" (size, align: int) -> int {
result := size + align-1
return result - result%align
}
+/*
+Calculate the padding for header preceding aligned data.
+
+This procedure returns the padding, following the specified pointer `ptr` that
+will be able to fit in a header of the size `header_size`, immediately
+preceding the memory region, aligned on a boundary specified by `align`. See
+the following diagram for a visual representation.
+
+ header size
+ |<------>|
+ +---+--------+------------- - - -
+ | HEADER | DATA...
+ +---+--------+------------- - - -
+ ^ ^
+ |<---------->|
+ | padding |
+ ptr aligned ptr
+
+The function takes in `ptr` and `header_size`, as well as the required
+alignment for `DATA`. The return value of the function is the padding between
+`ptr` and `aligned_ptr` that will be able to fit the header.
+*/
@(require_results)
calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, header_size: int) -> int {
p, a := ptr, align
modulo := p & (a-1)
-
padding := uintptr(0)
if modulo != 0 {
padding = a - modulo
}
-
needed_space := uintptr(header_size)
if padding < needed_space {
needed_space -= padding
-
if needed_space & (a-1) > 0 {
padding += align * (1+(needed_space/align))
} else {
padding += align * (needed_space/align)
}
}
-
return int(padding)
}
-
-
@(require_results, deprecated="prefer 'slice.clone'")
clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) {
new_slice, _ = make(T, len(slice), allocator, loc)
diff --git a/core/mem/mutex_allocator.odin b/core/mem/mutex_allocator.odin
index 591703eab..b8062bca1 100644
--- a/core/mem/mutex_allocator.odin
+++ b/core/mem/mutex_allocator.odin
@@ -1,19 +1,33 @@
-//+build !freestanding
+#+build !freestanding
package mem
import "core:sync"
+/*
+The data for mutex allocator.
+*/
Mutex_Allocator :: struct {
backing: Allocator,
mutex: sync.Mutex,
}
+/*
+Initialize the mutex allocator.
+
+This procedure initializes the mutex allocator using `backin_allocator` as the
+allocator that will be used to pass all allocation requests through.
+*/
mutex_allocator_init :: proc(m: ^Mutex_Allocator, backing_allocator: Allocator) {
m.backing = backing_allocator
m.mutex = {}
}
+/*
+Mutex allocator.
+The mutex allocator is a wrapper for allocators that is used to serialize all
+allocator requests across multiple threads.
+*/
@(require_results)
mutex_allocator :: proc(m: ^Mutex_Allocator) -> Allocator {
return Allocator{
@@ -22,11 +36,16 @@ mutex_allocator :: proc(m: ^Mutex_Allocator) -> Allocator {
}
}
-mutex_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
+mutex_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size: int,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> (result: []byte, err: Allocator_Error) {
m := (^Mutex_Allocator)(allocator_data)
-
sync.mutex_guard(&m.mutex)
return m.backing.procedure(m.backing.data, mode, size, alignment, old_memory, old_size, loc)
}
diff --git a/core/mem/raw.odin b/core/mem/raw.odin
index f56206957..41c91555e 100644
--- a/core/mem/raw.odin
+++ b/core/mem/raw.odin
@@ -3,26 +3,100 @@ package mem
import "base:builtin"
import "base:runtime"
-Raw_Any :: runtime.Raw_Any
-Raw_String :: runtime.Raw_String
-Raw_Cstring :: runtime.Raw_Cstring
-Raw_Slice :: runtime.Raw_Slice
+/*
+Memory layout of the `any` type.
+*/
+Raw_Any :: runtime.Raw_Any
+
+/*
+Memory layout of the `string` type.
+*/
+Raw_String :: runtime.Raw_String
+
+/*
+Memory layout of the `cstring` type.
+*/
+Raw_Cstring :: runtime.Raw_Cstring
+
+/*
+Memory layout of `[]T` types.
+*/
+Raw_Slice :: runtime.Raw_Slice
+
+/*
+Memory layout of `[dynamic]T` types.
+*/
Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array
-Raw_Map :: runtime.Raw_Map
-Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer
-Raw_Complex32 :: runtime.Raw_Complex32
-Raw_Complex64 :: runtime.Raw_Complex64
-Raw_Complex128 :: runtime.Raw_Complex128
-Raw_Quaternion64 :: runtime.Raw_Quaternion64
+/*
+Memory layout of `map[K]V` types.
+*/
+Raw_Map :: runtime.Raw_Map
+
+/*
+Memory layout of `#soa []T` types.
+*/
+Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer
+
+/*
+Memory layout of the `complex32` type.
+*/
+Raw_Complex32 :: runtime.Raw_Complex32
+
+/*
+Memory layout of the `complex64` type.
+*/
+Raw_Complex64 :: runtime.Raw_Complex64
+
+/*
+Memory layout of the `complex128` type.
+*/
+Raw_Complex128 :: runtime.Raw_Complex128
+
+/*
+Memory layout of the `quaternion64` type.
+*/
+Raw_Quaternion64 :: runtime.Raw_Quaternion64
+
+/*
+Memory layout of the `quaternion128` type.
+*/
Raw_Quaternion128 :: runtime.Raw_Quaternion128
+
+/*
+Memory layout of the `quaternion256` type.
+*/
Raw_Quaternion256 :: runtime.Raw_Quaternion256
-Raw_Quaternion64_Vector_Scalar :: runtime.Raw_Quaternion64_Vector_Scalar
+
+/*
+Memory layout of the `quaternion64` type.
+*/
+Raw_Quaternion64_Vector_Scalar :: runtime.Raw_Quaternion64_Vector_Scalar
+
+/*
+Memory layout of the `quaternion128` type.
+*/
Raw_Quaternion128_Vector_Scalar :: runtime.Raw_Quaternion128_Vector_Scalar
+
+/*
+Memory layout of the `quaternion256` type.
+*/
Raw_Quaternion256_Vector_Scalar :: runtime.Raw_Quaternion256_Vector_Scalar
+/*
+Create a value of the any type.
+
+This procedure creates a value with type `any` that points to an object with
+typeid `id` located at an address specified by `data`.
+*/
make_any :: proc "contextless" (data: rawptr, id: typeid) -> any {
return transmute(any)Raw_Any{data, id}
}
+/*
+Obtain pointer to the data.
+
+This procedure returns the pointer to the data of a slice, string, or a dynamic
+array.
+*/
raw_data :: builtin.raw_data
diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin
index f5e428d87..43ef10fe9 100644
--- a/core/mem/rollback_stack_allocator.odin
+++ b/core/mem/rollback_stack_allocator.odin
@@ -1,52 +1,36 @@
package mem
-// The Rollback Stack Allocator was designed for the test runner to be fast,
-// able to grow, and respect the Tracking Allocator's requirement for
-// individual frees. It is not overly concerned with fragmentation, however.
-//
-// It has support for expansion when configured with a block allocator and
-// limited support for out-of-order frees.
-//
-// Allocation has constant-time best and usual case performance.
-// At worst, it is linear according to the number of memory blocks.
-//
-// Allocation follows a first-fit strategy when there are multiple memory
-// blocks.
-//
-// Freeing has constant-time best and usual case performance.
-// At worst, it is linear according to the number of memory blocks and number
-// of freed items preceding the last item in a block.
-//
-// Resizing has constant-time performance, if it's the last item in a block, or
-// the new size is smaller. Naturally, this becomes linear-time if there are
-// multiple blocks to search for the pointer's owning block. Otherwise, the
-// allocator defaults to a combined alloc & free operation internally.
-//
-// Out-of-order freeing is accomplished by collapsing a run of freed items
-// from the last allocation backwards.
-//
-// Each allocation has an overhead of 8 bytes and any extra bytes to satisfy
-// the requested alignment.
-
import "base:runtime"
+/*
+Rollback stack default block size.
+*/
ROLLBACK_STACK_DEFAULT_BLOCK_SIZE :: 4 * Megabyte
-// This limitation is due to the size of `prev_ptr`, but it is only for the
-// head block; any allocation in excess of the allocator's `block_size` is
-// valid, so long as the block allocator can handle it.
-//
-// This is because allocations over the block size are not split up if the item
-// within is freed; they are immediately returned to the block allocator.
-ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE :: 2 * Gigabyte
+/*
+Rollback stack max head block size.
+This limitation is due to the size of `prev_ptr`, but it is only for the
+head block; any allocation in excess of the allocator's `block_size` is
+valid, so long as the block allocator can handle it.
+
+This is because allocations over the block size are not split up if the item
+within is freed; they are immediately returned to the block allocator.
+*/
+ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE :: 2 * Gigabyte
+/*
+Allocation header of the rollback stack allocator.
+*/
Rollback_Stack_Header :: bit_field u64 {
prev_offset: uintptr | 32,
is_free: bool | 1,
prev_ptr: uintptr | 31,
}
+/*
+Block header of the rollback stack allocator.
+*/
Rollback_Stack_Block :: struct {
next_block: ^Rollback_Stack_Block,
last_alloc: rawptr,
@@ -54,13 +38,15 @@ Rollback_Stack_Block :: struct {
buffer: []byte,
}
+/*
+Rollback stack allocator data.
+*/
Rollback_Stack :: struct {
head: ^Rollback_Stack_Block,
block_size: int,
block_allocator: Allocator,
}
-
@(private="file", require_results)
rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool {
start := raw_data(block.buffer)
@@ -110,6 +96,9 @@ rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_
}
}
+/*
+Free memory to a rollback stack allocator.
+*/
@(private="file", require_results)
rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error {
parent, block, header := rb_find_ptr(stack, ptr) or_return
@@ -128,6 +117,9 @@ rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error {
return nil
}
+/*
+Free all memory owned by the rollback stack allocator.
+*/
@(private="file")
rb_free_all :: proc(stack: ^Rollback_Stack) {
for block := stack.head.next_block; block != nil; /**/ {
@@ -141,45 +133,75 @@ rb_free_all :: proc(stack: ^Rollback_Stack) {
stack.head.offset = 0
}
-@(private="file", require_results)
-rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment: int) -> (result: []byte, err: Allocator_Error) {
- if ptr != nil {
- if block, _, ok := rb_find_last_alloc(stack, ptr); ok {
- // `block.offset` should never underflow because it is contingent
- // on `old_size` in the first place, assuming sane arguments.
- assert(block.offset >= cast(uintptr)old_size, "Rollback Stack Allocator received invalid `old_size`.")
-
- if block.offset + cast(uintptr)size - cast(uintptr)old_size < cast(uintptr)len(block.buffer) {
- // Prevent singleton allocations from fragmenting by forbidding
- // them to shrink, removing the possibility of overflow bugs.
- if len(block.buffer) <= stack.block_size {
- block.offset += cast(uintptr)size - cast(uintptr)old_size
- }
- #no_bounds_check return (cast([^]byte)ptr)[:size], nil
- }
- }
+/*
+Allocate memory using the rollback stack allocator.
+*/
+@(require_results)
+rb_alloc :: proc(
+ stack: ^Rollback_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := rb_alloc_bytes_non_zeroed(stack, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
}
+ return raw_data(bytes), err
+}
- result = rb_alloc(stack, size, alignment) or_return
- runtime.mem_copy_non_overlapping(raw_data(result), ptr, old_size)
- err = rb_free(stack, ptr)
+/*
+Allocate memory using the rollback stack allocator.
+*/
+@(require_results)
+rb_alloc_bytes :: proc(
+ stack: ^Rollback_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]byte, Allocator_Error) {
+ bytes, err := rb_alloc_bytes_non_zeroed(stack, size, alignment, loc)
+ if bytes != nil {
+ zero_slice(bytes)
+ }
+ return bytes, err
+}
- return
+/*
+Allocate non-initialized memory using the rollback stack allocator.
+*/
+@(require_results)
+rb_alloc_non_zeroed :: proc(
+ stack: ^Rollback_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := rb_alloc_bytes_non_zeroed(stack, size, alignment, loc)
+ return raw_data(bytes), err
}
-@(private="file", require_results)
-rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byte, err: Allocator_Error) {
+/*
+Allocate non-initialized memory using the rollback stack allocator.
+*/
+@(require_results)
+rb_alloc_bytes_non_zeroed :: proc(
+ stack: ^Rollback_Stack,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (result: []byte, err: Allocator_Error) {
+ assert(size >= 0, "Size must be positive or zero.", loc)
+ assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", loc)
parent: ^Rollback_Stack_Block
for block := stack.head; /**/; block = block.next_block {
when !ODIN_DISABLE_ASSERT {
allocated_new_block: bool
}
-
if block == nil {
if stack.block_allocator.procedure == nil {
return nil, .Out_Of_Memory
}
-
minimum_size_required := size_of(Rollback_Stack_Header) + size + alignment - 1
new_block_size := max(minimum_size_required, stack.block_size)
block = rb_make_block(new_block_size, stack.block_allocator) or_return
@@ -188,10 +210,8 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt
allocated_new_block = true
}
}
-
start := raw_data(block.buffer)[block.offset:]
padding := cast(uintptr)calc_padding_with_header(cast(uintptr)start, cast(uintptr)alignment, size_of(Rollback_Stack_Header))
-
if block.offset + padding + cast(uintptr)size > cast(uintptr)len(block.buffer) {
when !ODIN_DISABLE_ASSERT {
if allocated_new_block {
@@ -201,54 +221,150 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt
parent = block
continue
}
-
header := cast(^Rollback_Stack_Header)(start[padding - size_of(Rollback_Stack_Header):])
ptr := start[padding:]
-
header^ = {
prev_offset = block.offset,
prev_ptr = uintptr(0) if block.last_alloc == nil else cast(uintptr)block.last_alloc - cast(uintptr)raw_data(block.buffer),
is_free = false,
}
-
block.last_alloc = ptr
block.offset += padding + cast(uintptr)size
-
if len(block.buffer) > stack.block_size {
// This block exceeds the allocator's standard block size and is considered a singleton.
// Prevent any further allocations on it.
block.offset = cast(uintptr)len(block.buffer)
}
-
#no_bounds_check return ptr[:size], nil
}
-
return nil, .Out_Of_Memory
}
+/*
+Resize an allocation owned by rollback stack allocator.
+*/
+@(require_results)
+rb_resize :: proc(
+ stack: ^Rollback_Stack,
+ old_ptr: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := rb_resize_bytes_non_zeroed(stack, byte_slice(old_ptr, old_size), size, alignment, loc)
+ if bytes != nil {
+ if old_ptr == nil {
+ zero_slice(bytes)
+ } else if size > old_size {
+ zero_slice(bytes[old_size:])
+ }
+ }
+ return raw_data(bytes), err
+}
+
+/*
+Resize an allocation owned by rollback stack allocator.
+*/
+@(require_results)
+rb_resize_bytes :: proc(
+ stack: ^Rollback_Stack,
+ old_memory: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> ([]u8, Allocator_Error) {
+ bytes, err := rb_resize_bytes_non_zeroed(stack, old_memory, size, alignment, loc)
+ if bytes != nil {
+ if old_memory == nil {
+ zero_slice(bytes)
+ } else if size > len(old_memory) {
+ zero_slice(bytes[len(old_memory):])
+ }
+ }
+ return bytes, err
+}
+
+/*
+Resize an allocation owned by rollback stack allocator without explicit
+zero-initialization.
+*/
+@(require_results)
+rb_resize_non_zeroed :: proc(
+ stack: ^Rollback_Stack,
+ old_ptr: rawptr,
+ old_size: int,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (rawptr, Allocator_Error) {
+ bytes, err := rb_resize_bytes_non_zeroed(stack, byte_slice(old_ptr, old_size), size, alignment, loc)
+ return raw_data(bytes), err
+}
+
+/*
+Resize an allocation owned by rollback stack allocator without explicit
+zero-initialization.
+*/
+@(require_results)
+rb_resize_bytes_non_zeroed :: proc(
+ stack: ^Rollback_Stack,
+ old_memory: []byte,
+ size: int,
+ alignment := DEFAULT_ALIGNMENT,
+ loc := #caller_location,
+) -> (result: []byte, err: Allocator_Error) {
+ old_size := len(old_memory)
+ ptr := raw_data(old_memory)
+ assert(size >= 0, "Size must be positive or zero.", loc)
+ assert(old_size >= 0, "Old size must be positive or zero.", loc)
+ assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", loc)
+ if ptr != nil {
+ if block, _, ok := rb_find_last_alloc(stack, ptr); ok {
+ // `block.offset` should never underflow because it is contingent
+ // on `old_size` in the first place, assuming sane arguments.
+ assert(block.offset >= cast(uintptr)old_size, "Rollback Stack Allocator received invalid `old_size`.")
+ if block.offset + cast(uintptr)size - cast(uintptr)old_size < cast(uintptr)len(block.buffer) {
+ // Prevent singleton allocations from fragmenting by forbidding
+ // them to shrink, removing the possibility of overflow bugs.
+ if len(block.buffer) <= stack.block_size {
+ block.offset += cast(uintptr)size - cast(uintptr)old_size
+ }
+ #no_bounds_check return (ptr)[:size], nil
+ }
+ }
+ }
+ result = rb_alloc_bytes_non_zeroed(stack, size, alignment) or_return
+ runtime.mem_copy_non_overlapping(raw_data(result), ptr, old_size)
+ err = rb_free(stack, ptr)
+ return
+}
+
@(private="file", require_results)
rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stack_Block, err: Allocator_Error) {
buffer := runtime.mem_alloc(size_of(Rollback_Stack_Block) + size, align_of(Rollback_Stack_Block), allocator) or_return
-
block = cast(^Rollback_Stack_Block)raw_data(buffer)
#no_bounds_check block.buffer = buffer[size_of(Rollback_Stack_Block):]
return
}
-
+/*
+Initialize the rollback stack allocator using a fixed backing buffer.
+*/
rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, location := #caller_location) {
MIN_SIZE :: size_of(Rollback_Stack_Block) + size_of(Rollback_Stack_Header) + size_of(rawptr)
assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.", location)
-
block := cast(^Rollback_Stack_Block)raw_data(buffer)
block^ = {}
#no_bounds_check block.buffer = buffer[size_of(Rollback_Stack_Block):]
-
stack^ = {}
stack.head = block
stack.block_size = len(block.buffer)
}
+/*
+Initialize the rollback stack alocator using a backing block allocator.
+*/
rollback_stack_init_dynamic :: proc(
stack: ^Rollback_Stack,
block_size : int = ROLLBACK_STACK_DEFAULT_BLOCK_SIZE,
@@ -261,22 +377,25 @@ rollback_stack_init_dynamic :: proc(
// size is insufficient; check only on platforms with big enough ints.
assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.", location)
}
-
block := rb_make_block(block_size, block_allocator) or_return
-
stack^ = {}
stack.head = block
stack.block_size = block_size
stack.block_allocator = block_allocator
-
return nil
}
+/*
+Initialize the rollback stack.
+*/
rollback_stack_init :: proc {
rollback_stack_init_buffered,
rollback_stack_init_dynamic,
}
+/*
+Destroy a rollback stack.
+*/
rollback_stack_destroy :: proc(stack: ^Rollback_Stack) {
if stack.block_allocator.procedure != nil {
rb_free_all(stack)
@@ -285,6 +404,37 @@ rollback_stack_destroy :: proc(stack: ^Rollback_Stack) {
stack^ = {}
}
+/*
+Rollback stack allocator.
+
+The Rollback Stack Allocator was designed for the test runner to be fast,
+able to grow, and respect the Tracking Allocator's requirement for
+individual frees. It is not overly concerned with fragmentation, however.
+
+It has support for expansion when configured with a block allocator and
+limited support for out-of-order frees.
+
+Allocation has constant-time best and usual case performance.
+At worst, it is linear according to the number of memory blocks.
+
+Allocation follows a first-fit strategy when there are multiple memory
+blocks.
+
+Freeing has constant-time best and usual case performance.
+At worst, it is linear according to the number of memory blocks and number
+of freed items preceding the last item in a block.
+
+Resizing has constant-time performance, if it's the last item in a block, or
+the new size is smaller. Naturally, this becomes linear-time if there are
+multiple blocks to search for the pointer's owning block. Otherwise, the
+allocator defaults to a combined alloc & free operation internally.
+
+Out-of-order freeing is accomplished by collapsing a run of freed items
+from the last allocation backwards.
+
+Each allocation has an overhead of 8 bytes and any extra bytes to satisfy
+the requested alignment.
+*/
@(require_results)
rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator {
return Allocator {
@@ -294,48 +444,37 @@ rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator {
}
@(require_results)
-rollback_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, location := #caller_location,
+rollback_stack_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
) -> (result: []byte, err: Allocator_Error) {
stack := cast(^Rollback_Stack)allocator_data
-
switch mode {
- case .Alloc, .Alloc_Non_Zeroed:
- assert(size >= 0, "Size must be positive or zero.", location)
- assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", location)
- result = rb_alloc(stack, size, alignment) or_return
-
- if mode == .Alloc {
- zero_slice(result)
- }
-
+ case .Alloc:
+ return rb_alloc_bytes(stack, size, alignment, loc)
+ case .Alloc_Non_Zeroed:
+ return rb_alloc_bytes_non_zeroed(stack, size, alignment, loc)
case .Free:
- err = rb_free(stack, old_memory)
-
+ return nil, rb_free(stack, old_memory)
case .Free_All:
rb_free_all(stack)
-
- case .Resize, .Resize_Non_Zeroed:
- assert(size >= 0, "Size must be positive or zero.", location)
- assert(old_size >= 0, "Old size must be positive or zero.", location)
- assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", location)
- result = rb_resize(stack, old_memory, old_size, size, alignment) or_return
-
- #no_bounds_check if mode == .Resize && size > old_size {
- zero_slice(result[old_size:])
- }
-
+ return nil, nil
+ case .Resize:
+ return rb_resize_bytes(stack, byte_slice(old_memory, old_size), size, alignment, loc)
+ case .Resize_Non_Zeroed:
+ return rb_resize_bytes_non_zeroed(stack, byte_slice(old_memory, old_size), size, alignment, loc)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed}
}
return nil, nil
-
case .Query_Info:
return nil, .Mode_Not_Implemented
}
-
return
}
diff --git a/core/mem/tracking_allocator.odin b/core/mem/tracking_allocator.odin
index 1b57e5fb4..5da38e62f 100644
--- a/core/mem/tracking_allocator.odin
+++ b/core/mem/tracking_allocator.odin
@@ -1,53 +1,88 @@
-//+build !freestanding
+#+build !freestanding
package mem
import "base:runtime"
import "core:sync"
+/*
+Allocation entry for the tracking allocator.
+
+This structure stores the data related to an allocation.
+*/
Tracking_Allocator_Entry :: struct {
- memory: rawptr,
- size: int,
+ // Pointer to an allocated region.
+ memory: rawptr,
+ // Size of the allocated memory region.
+ size: int,
+ // Requested alignment.
alignment: int,
- mode: Allocator_Mode,
- err: Allocator_Error,
+ // Mode of the operation.
+ mode: Allocator_Mode,
+ // Error.
+ err: Allocator_Error,
+ // Location of the allocation.
location: runtime.Source_Code_Location,
}
+
+/*
+Bad free entry for a tracking allocator.
+*/
Tracking_Allocator_Bad_Free_Entry :: struct {
- memory: rawptr,
+ // Pointer, on which free operation was called.
+ memory: rawptr,
+ // The source location of where the operation was called.
location: runtime.Source_Code_Location,
}
+
+/*
+Tracking allocator data.
+*/
Tracking_Allocator :: struct {
- backing: Allocator,
- allocation_map: map[rawptr]Tracking_Allocator_Entry,
- bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
- mutex: sync.Mutex,
+ backing: Allocator,
+ allocation_map: map[rawptr]Tracking_Allocator_Entry,
+ bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
+ mutex: sync.Mutex,
clear_on_free_all: bool,
-
- total_memory_allocated: i64,
- total_allocation_count: i64,
- total_memory_freed: i64,
- total_free_count: i64,
- peak_memory_allocated: i64,
+ total_memory_allocated: i64,
+ total_allocation_count: i64,
+ total_memory_freed: i64,
+ total_free_count: i64,
+ peak_memory_allocated: i64,
current_memory_allocated: i64,
}
+/*
+Initialize the tracking allocator.
+
+This procedure initializes the tracking allocator `t` with a backing allocator
+specified with `backing_allocator`. The `internals_allocator` will used to
+allocate the tracked data.
+*/
tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) {
t.backing = backing_allocator
t.allocation_map.allocator = internals_allocator
t.bad_free_array.allocator = internals_allocator
-
if .Free_All in query_features(t.backing) {
t.clear_on_free_all = true
}
}
+/*
+Destroy the tracking allocator.
+*/
tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
delete(t.allocation_map)
delete(t.bad_free_array)
}
+/*
+Clear the tracking allocator.
+
+This procedure clears the tracked data from a tracking allocator.
-// Clear only the current allocation data while keeping the totals intact.
+**Note**: This procedure clears only the current allocation data while keeping
+the totals intact.
+*/
tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
sync.mutex_lock(&t.mutex)
clear(&t.allocation_map)
@@ -56,7 +91,11 @@ tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
sync.mutex_unlock(&t.mutex)
}
-// Reset all of a Tracking Allocator's allocation data back to zero.
+/*
+Reset the tracking allocator.
+
+Reset all of a Tracking Allocator's allocation data back to zero.
+*/
tracking_allocator_reset :: proc(t: ^Tracking_Allocator) {
sync.mutex_lock(&t.mutex)
clear(&t.allocation_map)
@@ -70,6 +109,39 @@ tracking_allocator_reset :: proc(t: ^Tracking_Allocator) {
sync.mutex_unlock(&t.mutex)
}
+/*
+Tracking allocator.
+
+The tracking allocator is an allocator wrapper that tracks memory allocations.
+This allocator stores all the allocations in a map. Whenever a pointer that's
+not inside of the map is freed, the `bad_free_array` entry is added.
+
+An example of how to use the `Tracking_Allocator` to track subsequent allocations
+in your program and report leaks and bad frees:
+
+Example:
+
+ package foo
+
+ import "core:mem"
+ import "core:fmt"
+
+ main :: proc() {
+ track: mem.Tracking_Allocator
+ mem.tracking_allocator_init(&track, context.allocator)
+ defer mem.tracking_allocator_destroy(&track)
+ context.allocator = mem.tracking_allocator(&track)
+
+ do_stuff()
+
+ for _, leak in track.allocation_map {
+ fmt.printf("%v leaked %m\n", leak.location, leak.size)
+ }
+ for bad_free in track.bad_free_array {
+ fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
+ }
+ }
+*/
@(require_results)
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
return Allocator{
@@ -78,9 +150,14 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
}
}
-tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
- size, alignment: int,
- old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
+tracking_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> (result: []byte, err: Allocator_Error) {
track_alloc :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) {
data.total_memory_allocated += i64(entry.size)
data.total_allocation_count += 1
diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin
index 80c231c31..79407d80d 100644
--- a/core/mem/virtual/arena.odin
+++ b/core/mem/virtual/arena.odin
@@ -49,6 +49,10 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
arena.total_used = 0
arena.total_reserved = arena.curr_block.reserved
+
+ if arena.minimum_block_size == 0 {
+ arena.minimum_block_size = reserved
+ }
return
}
diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin
index 4e53aba66..4afc33813 100644
--- a/core/mem/virtual/virtual.odin
+++ b/core/mem/virtual/virtual.odin
@@ -7,6 +7,11 @@ _ :: runtime
DEFAULT_PAGE_SIZE := uint(4096)
+@(init, private)
+platform_memory_init :: proc() {
+ _platform_memory_init()
+}
+
Allocator_Error :: mem.Allocator_Error
@(require_results)
diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin
index 0b4532baa..3e0d7668b 100644
--- a/core/mem/virtual/virtual_linux.odin
+++ b/core/mem/virtual/virtual_linux.odin
@@ -1,5 +1,5 @@
-//+build linux
-//+private
+#+build linux
+#+private
package mem_virtual
import "core:sys/linux"
diff --git a/core/mem/virtual/virtual_other.odin b/core/mem/virtual/virtual_other.odin
index 4fcb61b04..a57856975 100644
--- a/core/mem/virtual/virtual_other.odin
+++ b/core/mem/virtual/virtual_other.odin
@@ -1,10 +1,10 @@
-//+private
-//+build !darwin
-//+build !freebsd
-//+build !openbsd
-//+build !netbsd
-//+build !linux
-//+build !windows
+#+private
+#+build !darwin
+#+build !freebsd
+#+build !openbsd
+#+build !netbsd
+#+build !linux
+#+build !windows
package mem_virtual
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin
index c2b505cd2..54c42ce4b 100644
--- a/core/mem/virtual/virtual_platform.odin
+++ b/core/mem/virtual/virtual_platform.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package mem_virtual
Platform_Memory_Block :: struct {
diff --git a/core/mem/virtual/virtual_posix.odin b/core/mem/virtual/virtual_posix.odin
index fbe89abfa..105849774 100644
--- a/core/mem/virtual/virtual_posix.odin
+++ b/core/mem/virtual/virtual_posix.odin
@@ -1,5 +1,5 @@
-//+build darwin, netbsd, freebsd, openbsd
-//+private
+#+build darwin, netbsd, freebsd, openbsd
+#+private
package mem_virtual
import "core:sys/posix"
@@ -51,8 +51,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
}
_platform_memory_init :: proc() {
- DEFAULT_PAGE_SIZE = posix.PAGE_SIZE
-
+ // NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
+ size := posix.sysconf(._PAGESIZE)
+ DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
+
// is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
}
diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin
index ee47a01a8..acd30ae33 100644
--- a/core/mem/virtual/virtual_windows.odin
+++ b/core/mem/virtual/virtual_windows.odin
@@ -1,5 +1,5 @@
-//+build windows
-//+private
+#+build windows
+#+private
package mem_virtual
foreign import Kernel32 "system:Kernel32.lib"
diff --git a/core/net/addr.odin b/core/net/addr.odin
index 1972d8c22..c47c6f55e 100644
--- a/core/net/addr.odin
+++ b/core/net/addr.odin
@@ -1,4 +1,4 @@
-// +build windows, linux, darwin, freebsd
+#+build windows, linux, darwin, freebsd
package net
/*
diff --git a/core/net/common.odin b/core/net/common.odin
index ed255356e..263fc770f 100644
--- a/core/net/common.odin
+++ b/core/net/common.odin
@@ -1,4 +1,4 @@
-// +build windows, linux, darwin, freebsd
+#+build windows, linux, darwin, freebsd
package net
/*
diff --git a/core/net/dns.odin b/core/net/dns.odin
index e82b54262..ffb97fc5b 100644
--- a/core/net/dns.odin
+++ b/core/net/dns.odin
@@ -1,4 +1,4 @@
-// +build windows, linux, darwin, freebsd
+#+build windows, linux, darwin, freebsd
package net
/*
diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin
index 0448b8d9e..e4336e410 100644
--- a/core/net/dns_unix.odin
+++ b/core/net/dns_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd
+#+build linux, darwin, freebsd
package net
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/dns_windows.odin b/core/net/dns_windows.odin
index b7af050b1..2f3831767 100644
--- a/core/net/dns_windows.odin
+++ b/core/net/dns_windows.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package net
/*
@@ -128,33 +128,37 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
append(&recs, record)
case .SRV:
- target := strings.clone(string(r.Data.SRV.pNameTarget)) // The target hostname/address that the service can be found on
- priority := int(r.Data.SRV.wPriority)
- weight := int(r.Data.SRV.wWeight)
- port := int(r.Data.SRV.wPort)
-
// NOTE(tetra): Srv record name should be of the form '_servicename._protocol.hostname'
// The record name is the name of the record.
// Not to be confused with the _target_ of the record, which is--in combination with the port--what we're looking up
// by making this request in the first place.
- // NOTE(Jeroen): Service Name and Protocol Name can probably just be string slices into the record name.
- // It's already cloned, after all. I wouldn't put them on the temp allocator like this.
+ service_name, protocol_name: string
+
+ s := base_record.record_name
+ i := strings.index_byte(s, '.')
+ if i > -1 {
+ service_name = s[:i]
+ s = s[len(service_name) + 1:]
+ } else {
+ continue
+ }
- parts := strings.split_n(base_record.record_name, ".", 3, context.temp_allocator)
- if len(parts) != 3 {
+ i = strings.index_byte(s, '.')
+ if i > -1 {
+ protocol_name = s[:i]
+ } else {
continue
}
- service_name, protocol_name := parts[0], parts[1]
append(&recs, DNS_Record_SRV {
base = base_record,
- target = target,
- port = port,
+ target = strings.clone(string(r.Data.SRV.pNameTarget)), // The target hostname/address that the service can be found on
+ port = int(r.Data.SRV.wPort),
service_name = service_name,
protocol_name = protocol_name,
- priority = priority,
- weight = weight,
+ priority = int(r.Data.SRV.wPriority),
+ weight = int(r.Data.SRV.wWeight),
})
}
diff --git a/core/net/doc.odin b/core/net/doc.odin
index 996f8147e..ed720c0ae 100644
--- a/core/net/doc.odin
+++ b/core/net/doc.odin
@@ -13,36 +13,34 @@
*/
/*
- Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
- For other protocols and their features, see subdirectories of this package.
-
- Features:
- - Supports Windows, Linux and OSX.
- - Opening and closing of TCP and UDP sockets.
- - Sending to and receiving from these sockets.
- - DNS name lookup, using either the OS or our own resolver.
-
- Planned:
- - Nonblocking IO
- - `Connection` struct
- A "fat socket" struct that remembers how you opened it, etc, instead of just being a handle.
- - IP Range structs, CIDR/class ranges, netmask calculator and associated helper procedures.
- - Use `context.temp_allocator` instead of stack-based arenas?
- And check it's the default temp allocator or can give us 4 MiB worth of memory
- without punting to the main allocator by comparing their addresses in an @(init) procedure.
- Panic if this assumption is not met.
-
- - Document assumptions about libc usage (or avoidance thereof) for each platform.
-
- Assumptions:
- - For performance reasons this package relies on the `context.temp_allocator` in some places.
-
- You can replace the default `context.temp_allocator` with your own as long as it meets
- this requirement: A minimum of 4 MiB of scratch space that's expected not to be freed.
-
- If this expectation is not met, the package's @(init) procedure will attempt to detect
- this and panic to avoid temp allocations prematurely overwriting data and garbling results,
- or worse. This means that should you replace the temp allocator with an insufficient one,
- we'll do our best to loudly complain the first time you try it.
+Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
+For other protocols and their features, see subdirectories of this package.
+
+Features:
+- Supports Windows, Linux and OSX.
+- Opening and closing of TCP and UDP sockets.
+- Sending to and receiving from these sockets.
+- DNS name lookup, using either the OS or our own resolver.
+
+Planned:
+- Nonblocking IO
+- `Connection` struct; A "fat socket" struct that remembers how you opened it, etc, instead of just being a handle.
+- IP Range structs, CIDR/class ranges, netmask calculator and associated helper procedures.
+- Use `context.temp_allocator` instead of stack-based arenas?
+And check it's the default temp allocator or can give us 4 MiB worth of memory
+without punting to the main allocator by comparing their addresses in an @(init) procedure.
+Panic if this assumption is not met.
+- Document assumptions about libc usage (or avoidance thereof) for each platform.
+
+Assumptions:
+For performance reasons this package relies on the `context.temp_allocator` in some places.
+
+You can replace the default `context.temp_allocator` with your own as long as it meets
+this requirement: A minimum of 4 MiB of scratch space that's expected not to be freed.
+
+If this expectation is not met, the package's @(init) procedure will attempt to detect
+this and panic to avoid temp allocations prematurely overwriting data and garbling results,
+or worse. This means that should you replace the temp allocator with an insufficient one,
+we'll do our best to loudly complain the first time you try it.
*/
-package net \ No newline at end of file
+package net
diff --git a/core/net/errors_darwin.odin b/core/net/errors_darwin.odin
index f2a0d6262..2905b44bc 100644
--- a/core/net/errors_darwin.odin
+++ b/core/net/errors_darwin.odin
@@ -1,5 +1,5 @@
+#+build darwin
package net
-// +build darwin
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/errors_freebsd.odin b/core/net/errors_freebsd.odin
index 4830d1c03..486732a95 100644
--- a/core/net/errors_freebsd.odin
+++ b/core/net/errors_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package net
/*
diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin
index 9047b4020..3cd51e6fd 100644
--- a/core/net/errors_linux.odin
+++ b/core/net/errors_linux.odin
@@ -1,5 +1,5 @@
+#+build linux
package net
-// +build linux
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin
index ae928a05c..f41bcf888 100644
--- a/core/net/errors_windows.odin
+++ b/core/net/errors_windows.odin
@@ -1,5 +1,5 @@
+#+build windows
package net
-// +build windows
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/interface.odin b/core/net/interface.odin
index 90444fb63..775a812f3 100644
--- a/core/net/interface.odin
+++ b/core/net/interface.odin
@@ -1,4 +1,4 @@
-// +build windows, linux, darwin, freebsd
+#+build windows, linux, darwin, freebsd
package net
/*
diff --git a/core/net/interface_darwin.odin b/core/net/interface_darwin.odin
index 7a33682de..4921bc3fe 100644
--- a/core/net/interface_darwin.odin
+++ b/core/net/interface_darwin.odin
@@ -1,5 +1,5 @@
+#+build darwin
package net
-//+build darwin
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/interface_freebsd.odin b/core/net/interface_freebsd.odin
index a9a125299..50e2d1a96 100644
--- a/core/net/interface_freebsd.odin
+++ b/core/net/interface_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package net
/*
diff --git a/core/net/interface_linux.odin b/core/net/interface_linux.odin
index c6df8f0a2..28724735b 100644
--- a/core/net/interface_linux.odin
+++ b/core/net/interface_linux.odin
@@ -1,5 +1,5 @@
+#+build linux
package net
-//+build linux
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/interface_windows.odin b/core/net/interface_windows.odin
index 67da6d034..a6eb72846 100644
--- a/core/net/interface_windows.odin
+++ b/core/net/interface_windows.odin
@@ -1,5 +1,5 @@
+#+build windows
package net
-//+build windows
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
diff --git a/core/net/socket.odin b/core/net/socket.odin
index e36c67d21..950c7ac11 100644
--- a/core/net/socket.odin
+++ b/core/net/socket.odin
@@ -1,4 +1,4 @@
-// +build windows, linux, darwin, freebsd
+#+build windows, linux, darwin, freebsd
package net
/*
@@ -134,6 +134,13 @@ listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TC
return _listen_tcp(interface_endpoint, backlog)
}
+/*
+ Returns the endpoint that the given socket is listening / bound on.
+*/
+bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Network_Error) {
+ return _bound_endpoint(socket)
+}
+
accept_tcp :: proc(socket: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
return _accept_tcp(socket, options)
}
diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin
index a56d36de6..ec9255c3b 100644
--- a/core/net/socket_darwin.odin
+++ b/core/net/socket_darwin.odin
@@ -1,5 +1,5 @@
+#+build darwin
package net
-// +build darwin
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
@@ -22,6 +22,7 @@ package net
import "core:c"
import "core:os"
+import "core:sys/posix"
import "core:time"
Socket_Option :: enum c.int {
@@ -139,6 +140,19 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_
}
@(private)
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) {
+ addr: posix.sockaddr_storage
+ addr_len := posix.socklen_t(size_of(addr))
+ res := posix.getsockname(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len)
+ if res != .OK {
+ err = Listen_Error(posix.errno())
+ return
+ }
+ ep = _sockaddr_to_endpoint((^os.SOCKADDR_STORAGE_LH)(&addr))
+ return
+}
+
+@(private)
_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
sockaddr: os.SOCKADDR_STORAGE_LH
sockaddrlen := c.int(size_of(sockaddr))
diff --git a/core/net/socket_freebsd.odin b/core/net/socket_freebsd.odin
index 00da5ec06..0f3a85cbb 100644
--- a/core/net/socket_freebsd.odin
+++ b/core/net/socket_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package net
/*
@@ -150,6 +150,20 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T
}
@(private)
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) {
+ sockaddr: freebsd.Socket_Address_Storage
+
+ errno := freebsd.getsockname(cast(Fd)any_socket_to_socket(sock), &sockaddr)
+ if errno != nil {
+ err = cast(Listen_Error)errno
+ return
+ }
+
+ ep = _sockaddr_to_endpoint(&sockaddr)
+ return
+}
+
+@(private)
_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
sockaddr: freebsd.Socket_Address_Storage
diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin
index 52f328814..a3853874a 100644
--- a/core/net/socket_linux.odin
+++ b/core/net/socket_linux.odin
@@ -1,5 +1,5 @@
+#+build linux
package net
-// +build linux
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
@@ -203,6 +203,19 @@ _listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (TCP_Socket, Network
}
@(private)
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) {
+ addr: linux.Sock_Addr_Any
+ errno := linux.getsockname(_unwrap_os_socket(sock), &addr)
+ if errno != .NONE {
+ err = Listen_Error(errno)
+ return
+ }
+
+ ep = _wrap_os_addr(addr)
+ return
+}
+
+@(private)
_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (tcp_client: TCP_Socket, endpoint: Endpoint, err: Network_Error) {
addr: linux.Sock_Addr_Any
client_sock, errno := linux.accept(linux.Fd(sock), &addr)
diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin
index 8ee75bc3b..20f17619d 100644
--- a/core/net/socket_windows.odin
+++ b/core/net/socket_windows.odin
@@ -1,5 +1,5 @@
+#+build windows
package net
-// +build windows
/*
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
@@ -121,6 +121,19 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T
}
@(private)
+_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) {
+ sockaddr: win.SOCKADDR_STORAGE_LH
+ sockaddrlen := c.int(size_of(sockaddr))
+ if win.getsockname(win.SOCKET(any_socket_to_socket(sock)), &sockaddr, &sockaddrlen) == win.SOCKET_ERROR {
+ err = Listen_Error(win.WSAGetLastError())
+ return
+ }
+
+ ep = _sockaddr_to_endpoint(&sockaddr)
+ return
+}
+
+@(private)
_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
for {
sockaddr: win.SOCKADDR_STORAGE_LH
@@ -368,4 +381,4 @@ _sockaddr_to_endpoint :: proc(native_addr: ^win.SOCKADDR_STORAGE_LH) -> (ep: End
panic("native_addr is neither IP4 or IP6 address")
}
return
-} \ No newline at end of file
+}
diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin
index 075a669de..d67eb31f3 100644
--- a/core/odin/ast/ast.odin
+++ b/core/odin/ast/ast.odin
@@ -27,6 +27,8 @@ Proc_Calling_Convention :: union {
Node_State_Flag :: enum {
Bounds_Check,
No_Bounds_Check,
+ Type_Assert,
+ No_Type_Assert,
}
Node_State_Flags :: distinct bit_set[Node_State_Flag]
@@ -67,6 +69,7 @@ File :: struct {
fullpath: string,
src: string,
+ tags: [dynamic]tokenizer.Token,
docs: ^Comment_Group,
pkg_decl: ^Package_Decl,
diff --git a/core/odin/parser/file_tags.odin b/core/odin/parser/file_tags.odin
new file mode 100644
index 000000000..84b172148
--- /dev/null
+++ b/core/odin/parser/file_tags.odin
@@ -0,0 +1,258 @@
+package odin_parser
+
+import "base:runtime"
+import "core:strings"
+import "core:reflect"
+
+import "../ast"
+
+Private_Flag :: enum {
+ Public,
+ Package,
+ File,
+}
+
+Build_Kind :: struct {
+ os: runtime.Odin_OS_Types,
+ arch: runtime.Odin_Arch_Types,
+}
+
+File_Tags :: struct {
+ build_project_name: [][]string,
+ build: []Build_Kind,
+ private: Private_Flag,
+ ignore: bool,
+ lazy: bool,
+ no_instrumentation: bool,
+}
+
+@require_results
+get_build_os_from_string :: proc(str: string) -> runtime.Odin_OS_Type {
+ fields := reflect.enum_fields_zipped(runtime.Odin_OS_Type)
+ for os in fields {
+ if strings.equal_fold(os.name, str) {
+ return runtime.Odin_OS_Type(os.value)
+ }
+ }
+ return .Unknown
+}
+@require_results
+get_build_arch_from_string :: proc(str: string) -> runtime.Odin_Arch_Type {
+ fields := reflect.enum_fields_zipped(runtime.Odin_Arch_Type)
+ for os in fields {
+ if strings.equal_fold(os.name, str) {
+ return runtime.Odin_Arch_Type(os.value)
+ }
+ }
+ return .Unknown
+}
+
+@require_results
+parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags: File_Tags) {
+ context.allocator = allocator
+
+ if file.docs == nil && file.tags == nil {
+ return
+ }
+
+ next_char :: proc(src: string, i: ^int) -> (ch: u8) {
+ if i^ < len(src) {
+ ch = src[i^]
+ }
+ i^ += 1
+ return
+ }
+ skip_whitespace :: proc(src: string, i: ^int) {
+ for {
+ switch next_char(src, i) {
+ case ' ', '\t':
+ continue
+ case:
+ i^ -= 1
+ return
+ }
+ }
+ }
+ scan_value :: proc(src: string, i: ^int) -> string {
+ start := i^
+ for {
+ switch next_char(src, i) {
+ case ' ', '\t', '\n', '\r', 0, ',':
+ i^ -= 1
+ return src[start:i^]
+ case:
+ continue
+ }
+ }
+ }
+
+ build_kinds: [dynamic]Build_Kind
+ defer shrink(&build_kinds)
+
+ build_project_name_strings: [dynamic]string
+ defer shrink(&build_project_name_strings)
+
+ build_project_names: [dynamic][]string
+ defer shrink(&build_project_names)
+
+ parse_tag :: proc(text: string, tags: ^File_Tags, build_kinds: ^[dynamic]Build_Kind,
+ build_project_name_strings: ^[dynamic]string,
+ build_project_names: ^[dynamic][]string) {
+ i := 0
+
+ skip_whitespace(text, &i)
+
+ if next_char(text, &i) == '+' {
+ switch scan_value(text, &i) {
+ case "ignore":
+ tags.ignore = true
+ case "lazy":
+ tags.lazy = true
+ case "no-instrumentation":
+ tags.no_instrumentation = true
+ case "private":
+ skip_whitespace(text, &i)
+ switch scan_value(text, &i) {
+ case "file":
+ tags.private = .File
+ case "package", "":
+ tags.private = .Package
+ }
+ case "build-project-name":
+ groups_loop: for {
+ index_start := len(build_project_name_strings)
+
+ defer append(build_project_names, build_project_name_strings[index_start:])
+
+ for {
+ skip_whitespace(text, &i)
+ name_start := i
+
+ switch next_char(text, &i) {
+ case 0, '\r', '\n':
+ i -= 1
+ break groups_loop
+ case ',':
+ continue groups_loop
+ case '!':
+ // include ! in the name
+ case:
+ i -= 1
+ }
+
+ scan_value(text, &i)
+ append(build_project_name_strings, text[name_start:i])
+ }
+
+ append(build_project_names, build_project_name_strings[index_start:])
+ }
+ case "build":
+ kinds_loop: for {
+ os_positive: runtime.Odin_OS_Types
+ os_negative: runtime.Odin_OS_Types
+
+ arch_positive: runtime.Odin_Arch_Types
+ arch_negative: runtime.Odin_Arch_Types
+
+ defer append(build_kinds, Build_Kind{
+ os = (os_positive == {} ? runtime.ALL_ODIN_OS_TYPES : os_positive) -os_negative,
+ arch = (arch_positive == {} ? runtime.ALL_ODIN_ARCH_TYPES : arch_positive)-arch_negative,
+ })
+
+ for {
+ skip_whitespace(text, &i)
+
+ is_notted: bool
+ switch next_char(text, &i) {
+ case 0, '\r', '\n':
+ i -= 1
+ break kinds_loop
+ case ',':
+ continue kinds_loop
+ case '!':
+ is_notted = true
+ case:
+ i -= 1
+ }
+
+ value := scan_value(text, &i)
+
+ if value == "ignore" {
+ tags.ignore = true
+ } else if os := get_build_os_from_string(value); os != .Unknown {
+ if is_notted {
+ os_negative += {os}
+ } else {
+ os_positive += {os}
+ }
+ } else if arch := get_build_arch_from_string(value); arch != .Unknown {
+ if is_notted {
+ arch_negative += {arch}
+ } else {
+ arch_positive += {arch}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if file.docs != nil {
+ for comment in file.docs.list {
+ if len(comment.text) < 3 || comment.text[:2] != "//" {
+ continue
+ }
+ text := comment.text[2:]
+
+ parse_tag(text, &tags, &build_kinds, &build_project_name_strings, &build_project_names)
+ }
+ }
+
+ for tag in file.tags {
+ if len(tag.text) < 3 || tag.text[:2] != "#+" {
+ continue
+ }
+ // Only skip # because parse_tag skips the plus
+ text := tag.text[1:]
+
+ parse_tag(text, &tags, &build_kinds, &build_project_name_strings, &build_project_names)
+ }
+
+ tags.build = build_kinds[:]
+ tags.build_project_name = build_project_names[:]
+
+ return
+}
+
+Build_Target :: struct {
+ os: runtime.Odin_OS_Type,
+ arch: runtime.Odin_Arch_Type,
+ project_name: string,
+}
+
+@require_results
+match_build_tags :: proc(file_tags: File_Tags, target: Build_Target) -> bool {
+
+ project_name_correct := len(target.project_name) == 0 || len(file_tags.build_project_name) == 0
+
+ for group in file_tags.build_project_name {
+ group_correct := true
+ for name in group {
+ if name[0] == '!' {
+ group_correct &&= target.project_name != name[1:]
+ } else {
+ group_correct &&= target.project_name == name
+ }
+ }
+ project_name_correct ||= group_correct
+ }
+
+ os_and_arch_correct := len(file_tags.build) == 0
+
+ for kind in file_tags.build {
+ os_and_arch_correct ||= target.os in kind.os && target.arch in kind.arch
+ }
+
+ return !file_tags.ignore && project_name_correct && os_and_arch_correct
+}
diff --git a/core/odin/parser/parse_files.odin b/core/odin/parser/parse_files.odin
index 5f455c749..d4e532ec7 100644
--- a/core/odin/parser/parse_files.odin
+++ b/core/odin/parser/parse_files.odin
@@ -77,9 +77,7 @@ parse_package :: proc(pkg: ^ast.Package, p: ^Parser = nil) -> bool {
if !parse_file(p, file) {
ok = false
}
- if file.pkg_decl == nil {
- error(p, p.curr_tok.pos, "Expected a package declaration at the start of the file")
- } else if pkg.name == "" {
+ if pkg.name == "" {
pkg.name = file.pkg_decl.name
} else if pkg.name != file.pkg_decl.name {
error(p, file.pkg_decl.pos, "different package name, expected '%s', got '%s'", pkg.name, file.pkg_decl.name)
diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin
index 991b05398..d42766bde 100644
--- a/core/odin/parser/parser.odin
+++ b/core/odin/parser/parser.odin
@@ -161,11 +161,36 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
docs := p.lead_comment
+ invalid_pre_package_token: Maybe(tokenizer.Token)
+
+ for p.curr_tok.kind != .Package && p.curr_tok.kind != .EOF {
+ if p.curr_tok.kind == .Comment {
+ consume_comment_groups(p, p.prev_tok)
+ } else if p.curr_tok.kind == .File_Tag {
+ append(&p.file.tags, p.curr_tok)
+ advance_token(p)
+ } else {
+ if invalid_pre_package_token == nil {
+ invalid_pre_package_token = p.curr_tok
+ }
+
+ advance_token(p)
+ }
+ }
+
+ if p.curr_tok.kind != .Package {
+ t := invalid_pre_package_token.? or_else p.curr_tok
+ error(p, t.pos, "Expected a package declaration at the start of the file")
+ return false
+ }
+
p.file.pkg_token = expect_token(p, .Package)
- if p.file.pkg_token.kind != .Package {
+
+ if ippt, ok := invalid_pre_package_token.?; ok {
+ error(p, ippt.pos, "Expected only comments or lines starting with '#+' before the package declaration")
return false
}
-
+
pkg_name := expect_token_after(p, .Ident, "package")
if pkg_name.kind == .Ident {
switch name := pkg_name.text; {
@@ -1438,6 +1463,15 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
stmt.state_flags += {.No_Bounds_Check}
}
return stmt
+ case "type_assert", "no_type_assert":
+ stmt := parse_stmt(p)
+ switch name {
+ case "type_assert":
+ stmt.state_flags += {.Type_Assert}
+ case "no_type_assert":
+ stmt.state_flags += {.No_Type_Assert}
+ }
+ return stmt
case "partial":
stmt := parse_stmt(p)
#partial switch s in stmt.derived_stmt {
@@ -2268,6 +2302,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
bd.name = name.text
return bd
+ case "caller_expression":
+ bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
+ bd.tok = tok
+ bd.name = name.text
+
+ if peek_token_kind(p, .Open_Paren) {
+ return parse_call_expr(p, bd)
+ }
+ return bd
+
case "location", "exists", "load", "load_directory", "load_hash", "hash", "assert", "panic", "defined", "config":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin
index cd8953841..48d08f127 100644
--- a/core/odin/tokenizer/token.odin
+++ b/core/odin/tokenizer/token.odin
@@ -32,6 +32,7 @@ Token_Kind :: enum u32 {
Invalid,
EOF,
Comment,
+ File_Tag,
B_Literal_Begin,
Ident, // main
@@ -166,6 +167,7 @@ tokens := [Token_Kind.COUNT]string {
"Invalid",
"EOF",
"Comment",
+ "FileTag",
"",
"identifier",
diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin
index 62170aa10..c3a30581c 100644
--- a/core/odin/tokenizer/tokenizer.odin
+++ b/core/odin/tokenizer/tokenizer.odin
@@ -206,6 +206,23 @@ scan_comment :: proc(t: ^Tokenizer) -> string {
return string(lit)
}
+scan_file_tag :: proc(t: ^Tokenizer) -> string {
+ offset := t.offset - 1
+
+ for t.ch != '\n' {
+ if t.ch == '/' {
+ next := peek_byte(t, 0)
+
+ if next == '/' || next == '*' {
+ break
+ }
+ }
+ advance_rune(t)
+ }
+
+ return string(t.src[offset : t.offset])
+}
+
scan_identifier :: proc(t: ^Tokenizer) -> string {
offset := t.offset
@@ -636,6 +653,9 @@ scan :: proc(t: ^Tokenizer) -> Token {
if t.ch == '!' {
kind = .Comment
lit = scan_comment(t)
+ } else if t.ch == '+' {
+ kind = .File_Tag
+ lit = scan_file_tag(t)
}
case '/':
kind = .Quo
diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin
index b472e89b7..26e865204 100644
--- a/core/os/dir_unix.odin
+++ b/core/os/dir_unix.odin
@@ -1,4 +1,4 @@
-//+build darwin, linux, netbsd, freebsd, openbsd
+#+build darwin, linux, netbsd, freebsd, openbsd
package os
import "core:strings"
diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin
index 3f6f781aa..375da6aff 100644
--- a/core/os/file_windows.odin
+++ b/core/os/file_windows.odin
@@ -192,6 +192,8 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
case 0: w = win32.FILE_BEGIN
case 1: w = win32.FILE_CURRENT
case 2: w = win32.FILE_END
+ case:
+ return 0, .Invalid_Whence
}
hi := i32(offset>>32)
lo := i32(offset)
@@ -223,11 +225,13 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
MAX_RW :: 1<<30
@(private)
-pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
+pread :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
+ curr_off := seek(fd, 0, 1) or_return
+ defer seek(fd, curr_off, 0)
+
buf := data
if len(buf) > MAX_RW {
buf = buf[:MAX_RW]
-
}
o := win32.OVERLAPPED{
@@ -247,11 +251,13 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
return int(done), e
}
@(private)
-pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
+pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
+ curr_off := seek(fd, 0, 1) or_return
+ defer seek(fd, curr_off, 0)
+
buf := data
if len(buf) > MAX_RW {
buf = buf[:MAX_RW]
-
}
o := win32.OVERLAPPED{
@@ -271,13 +277,6 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
/*
read_at returns n: 0, err: 0 on EOF
-on Windows, read_at changes the position of the file cursor, on *nix, it does not.
-
- bytes: [8]u8{}
- read_at(fd, bytes, 0)
- read(fd, bytes)
-
-will read from the location twice on *nix, and from two different locations on Windows
*/
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
if offset < 0 {
@@ -302,15 +301,6 @@ read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
return
}
-/*
-on Windows, write_at changes the position of the file cursor, on *nix, it does not.
-
- bytes: [8]u8{}
- write_at(fd, bytes, 0)
- write(fd, bytes)
-
-will write to the location twice on *nix, and to two different locations on Windows
-*/
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
if offset < 0 {
return 0, .Invalid_Offset
diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin
index 0ab3adfb2..a205cae48 100644
--- a/core/os/os2/allocators.odin
+++ b/core/os/os2/allocators.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
@@ -22,9 +22,14 @@ global_default_temp_allocator_index: uint
@(require_results)
temp_allocator :: proc() -> runtime.Allocator {
+ arena := &global_default_temp_allocator_arenas[global_default_temp_allocator_index]
+ if arena.backing_allocator.procedure == nil {
+ arena.backing_allocator = heap_allocator()
+ }
+
return runtime.Allocator{
procedure = temp_allocator_proc,
- data = &global_default_temp_allocator_arenas[global_default_temp_allocator_index],
+ data = arena,
}
}
@@ -61,3 +66,8 @@ TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
return tmp, loc
}
+
+@(init, private)
+init_thread_local_cleaner :: proc() {
+ runtime.add_thread_local_cleaner(temp_allocator_fini)
+}
diff --git a/core/os/os2/dir_linux.odin b/core/os/os2/dir_linux.odin
index d4f62e213..6a097e192 100644
--- a/core/os/os2/dir_linux.odin
+++ b/core/os/os2/dir_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
Read_Directory_Iterator_Impl :: struct {
diff --git a/core/os/os2/dir_posix.odin b/core/os/os2/dir_posix.odin
index 75f620d90..14fddde50 100644
--- a/core/os/os2/dir_posix.odin
+++ b/core/os/os2/dir_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "core:sys/posix"
diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin
index 1b9675064..09990aeec 100644
--- a/core/os/os2/dir_windows.odin
+++ b/core/os/os2/dir_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin
index 99dd00d90..c248a323c 100644
--- a/core/os/os2/env_linux.odin
+++ b/core/os/os2/env_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/env_posix.odin b/core/os/os2/env_posix.odin
index 93524fb0c..e2080485d 100644
--- a/core/os/os2/env_posix.odin
+++ b/core/os/os2/env_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin
index ac30eb1d4..a1e8c969d 100644
--- a/core/os/os2/env_windows.odin
+++ b/core/os/os2/env_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import win32 "core:sys/windows"
diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin
index 29815bf79..09492110d 100644
--- a/core/os/os2/errors_linux.odin
+++ b/core/os/os2/errors_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:sys/linux"
@@ -154,6 +154,14 @@ _get_platform_error :: proc(errno: linux.Errno) -> Error {
return .Exist
case .ENOENT:
return .Not_Exist
+ case .ETIMEDOUT:
+ return .Timeout
+ case .EPIPE:
+ return .Broken_Pipe
+ case .EBADF:
+ return .Invalid_File
+ case .ENOMEM:
+ return .Out_Of_Memory
}
return Platform_Error(i32(errno))
diff --git a/core/os/os2/errors_posix.odin b/core/os/os2/errors_posix.odin
index 9e3424a4a..59f0ba5f1 100644
--- a/core/os/os2/errors_posix.odin
+++ b/core/os/os2/errors_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "core:sys/posix"
diff --git a/core/os/os2/errors_windows.odin b/core/os/os2/errors_windows.odin
index 6748c1167..56acd503f 100644
--- a/core/os/os2/errors_windows.odin
+++ b/core/os/os2/errors_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
@@ -52,6 +52,9 @@ _get_platform_error :: proc() -> Error {
case win32.ERROR_INVALID_HANDLE:
return .Invalid_File
+ case win32.ERROR_NEGATIVE_SEEK:
+ return .Invalid_Offset
+
case
win32.ERROR_BAD_ARGUMENTS,
win32.ERROR_INVALID_PARAMETER,
diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin
index f1c5b1fad..eedf8570c 100644
--- a/core/os/os2/file.odin
+++ b/core/os/os2/file.odin
@@ -132,6 +132,12 @@ name :: proc(f: ^File) -> string {
return _name(f)
}
+/*
+ Close a file and its stream.
+
+ Any further use of the file or its stream should be considered to be in the
+ same class of bugs as a use-after-free.
+*/
close :: proc(f: ^File) -> Error {
if f != nil {
return io.close(f.stream)
diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin
index 64683cf1e..e9ce13447 100644
--- a/core/os/os2/file_linux.odin
+++ b/core/os/os2/file_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
@@ -170,11 +170,23 @@ _name :: proc(f: ^File) -> string {
}
_seek :: proc(f: ^File_Impl, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
+ // We have to handle this here, because Linux returns EINVAL for both
+ // invalid offsets and invalid whences.
+ switch whence {
+ case .Start, .Current, .End:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
n, errno := linux.lseek(f.fd, offset, linux.Seek_Whence(whence))
- if errno != .NONE {
+ #partial switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ case .NONE:
+ return n, nil
+ case:
return -1, _get_platform_error(errno)
}
- return n, nil
}
_read :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
@@ -189,6 +201,9 @@ _read :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
}
_read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
if offset < 0 {
return 0, .Invalid_Offset
}
@@ -214,6 +229,9 @@ _write :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
}
_write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
if offset < 0 {
return 0, .Invalid_Offset
}
diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin
index 96b7ffe4e..b7dc43287 100644
--- a/core/os/os2/file_posix.odin
+++ b/core/os/os2/file_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
@@ -419,9 +419,22 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
#assert(int(posix.Whence.CUR) == int(io.Seek_From.Current))
#assert(int(posix.Whence.END) == int(io.Seek_From.End))
+ switch whence {
+ case .Start, .Current, .End:
+ break
+ case:
+ err = .Invalid_Whence
+ return
+ }
+
n = i64(posix.lseek(fd, posix.off_t(offset), posix.Whence(whence)))
if n < 0 {
- err = .Unknown
+ #partial switch posix.get_errno() {
+ case .EINVAL:
+ err = .Invalid_Offset
+ case:
+ err = .Unknown
+ }
}
return
@@ -446,7 +459,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
return
case .Query:
- return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query})
+ return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
case:
return 0, .Empty
diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/os2/file_posix_darwin.odin
index 056d775e6..920a63a71 100644
--- a/core/os/os2/file_posix_darwin.odin
+++ b/core/os/os2/file_posix_darwin.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/file_posix_freebsd.odin b/core/os/os2/file_posix_freebsd.odin
index e5007f8fe..05d031930 100644
--- a/core/os/os2/file_posix_freebsd.odin
+++ b/core/os/os2/file_posix_freebsd.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/file_posix_netbsd.odin b/core/os/os2/file_posix_netbsd.odin
index a9cc77a41..f96c227ba 100644
--- a/core/os/os2/file_posix_netbsd.odin
+++ b/core/os/os2/file_posix_netbsd.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/file_posix_other.odin b/core/os/os2/file_posix_other.odin
index 929622578..74b6374ec 100644
--- a/core/os/os2/file_posix_other.odin
+++ b/core/os/os2/file_posix_other.odin
@@ -1,5 +1,5 @@
-//+private
-//+build openbsd
+#+private
+#+build openbsd
package os2
import "base:runtime"
diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin
index e328f9a02..963544985 100644
--- a/core/os/os2/file_util.odin
+++ b/core/os/os2/file_util.odin
@@ -125,9 +125,6 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
has_size = true
size = int(size64)
}
- } else if serr != .No_Size {
- err = serr
- return
}
if has_size && size > 0 {
diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin
index 74067464b..511935d74 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/os2/file_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
@@ -248,6 +248,8 @@ _seek :: proc(f: ^File_Impl, offset: i64, whence: io.Seek_From) -> (ret: i64, er
case .Start: w = win32.FILE_BEGIN
case .Current: w = win32.FILE_CURRENT
case .End: w = win32.FILE_END
+ case:
+ return 0, .Invalid_Whence
}
hi := i32(offset>>32)
lo := i32(offset)
@@ -264,6 +266,11 @@ _read :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) {
}
_read_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) {
+ length := len(p)
+ if length == 0 {
+ return
+ }
+
read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) {
if len(b) == 0 {
return 0, nil
@@ -318,7 +325,6 @@ _read_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) {
single_read_length: win32.DWORD
total_read: int
- length := len(p)
sync.shared_guard(&f.rw_mutex) // multiple readers
@@ -337,6 +343,10 @@ _read_internal :: proc(f: ^File_Impl, p: []byte) -> (n: i64, err: Error) {
if single_read_length > 0 && ok {
total_read += int(single_read_length)
+ } else if single_read_length == 0 && ok {
+ // ok and 0 bytes means EOF:
+ // https://learn.microsoft.com/en-us/windows/win32/fileio/testing-for-the-end-of-a-file
+ err = .EOF
} else {
err = _get_platform_error()
}
@@ -352,7 +362,7 @@ _read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (n: i64, err: Error)
buf = buf[:MAX_RW]
}
- curr_offset := _seek(f, offset, .Current) or_return
+ curr_offset := _seek(f, 0, .Current) or_return
defer _seek(f, curr_offset, .Start)
o := win32.OVERLAPPED{
@@ -421,7 +431,7 @@ _write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (n: i64, err: Error)
buf = buf[:MAX_RW]
}
- curr_offset := _seek(f, offset, .Current) or_return
+ curr_offset := _seek(f, 0, .Current) or_return
defer _seek(f, curr_offset, .Start)
o := win32.OVERLAPPED{
@@ -466,13 +476,13 @@ _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {
_sync :: proc(f: ^File) -> Error {
if f != nil && f.impl != nil {
- return _flush((^File_Impl)(f.impl))
+ return _flush_internal((^File_Impl)(f.impl))
}
return nil
}
_flush :: proc(f: ^File_Impl) -> Error {
- return _flush(f)
+ return _flush_internal(f)
}
_flush_internal :: proc(f: ^File_Impl) -> Error {
handle := _handle(&f.file)
@@ -813,7 +823,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
err = error_to_io_error(ferr)
return
case .Query:
- return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query})
+ return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
}
return 0, .Empty
}
diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin
index 11cf5ab41..ede5eb2ac 100644
--- a/core/os/os2/heap_linux.odin
+++ b/core/os/os2/heap_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:sys/linux"
@@ -280,7 +280,8 @@ heap_alloc :: proc(size: int) -> rawptr {
_local_region, back_idx = _region_retrieve_with_space(blocks_needed, local_region_idx, back_idx)
}
user_ptr, used := _region_get_block(_local_region, idx, blocks_needed)
- _local_region.hdr.free_blocks -= (used + 1)
+
+ sync.atomic_sub_explicit(&_local_region.hdr.free_blocks, used + 1, .Release)
// If this memory was ever used before, it now needs to be zero'd.
if idx < _local_region.hdr.last_used {
@@ -307,7 +308,7 @@ heap_resize :: proc(old_memory: rawptr, new_size: int) -> rawptr #no_bounds_chec
heap_free :: proc(memory: rawptr) {
alloc := _get_allocation_header(memory)
- if alloc.requested & IS_DIRECT_MMAP == IS_DIRECT_MMAP {
+ if sync.atomic_load(&alloc.requested) & IS_DIRECT_MMAP == IS_DIRECT_MMAP {
_direct_mmap_free(alloc)
return
}
@@ -462,25 +463,31 @@ _region_local_free :: proc(alloc: ^Allocation_Header) #no_bounds_check {
alloc := alloc
add_to_free_list := true
- _local_region.hdr.free_blocks += _get_block_count(alloc^) + 1
+ idx := sync.atomic_load(&alloc.idx)
+ prev := sync.atomic_load(&alloc.prev)
+ next := sync.atomic_load(&alloc.next)
+ block_count := next - idx - 1
+ free_blocks := sync.atomic_load(&_local_region.hdr.free_blocks) + block_count + 1
+ sync.atomic_store_explicit(&_local_region.hdr.free_blocks, free_blocks, .Release)
// try to merge with prev
- if alloc.idx > 0 && _local_region.memory[alloc.prev].free_idx != NOT_FREE {
- _local_region.memory[alloc.prev].next = alloc.next
- _local_region.memory[alloc.next].prev = alloc.prev
- alloc = &_local_region.memory[alloc.prev]
+ if idx > 0 && sync.atomic_load(&_local_region.memory[prev].free_idx) != NOT_FREE {
+ sync.atomic_store_explicit(&_local_region.memory[prev].next, next, .Release)
+ _local_region.memory[next].prev = prev
+ alloc = &_local_region.memory[prev]
add_to_free_list = false
}
// try to merge with next
- if alloc.next < BLOCKS_PER_REGION - 1 && _local_region.memory[alloc.next].free_idx != NOT_FREE {
- old_next := alloc.next
- alloc.next = _local_region.memory[old_next].next
- _local_region.memory[alloc.next].prev = alloc.idx
+ if next < BLOCKS_PER_REGION - 1 && sync.atomic_load(&_local_region.memory[next].free_idx) != NOT_FREE {
+ old_next := next
+ sync.atomic_store_explicit(&alloc.next, sync.atomic_load(&_local_region.memory[old_next].next), .Release)
+
+ sync.atomic_store_explicit(&_local_region.memory[next].prev, idx, .Release)
if add_to_free_list {
- _local_region.hdr.free_list[_local_region.memory[old_next].free_idx] = alloc.idx
- alloc.free_idx = _local_region.memory[old_next].free_idx
+ sync.atomic_store_explicit(&_local_region.hdr.free_list[_local_region.memory[old_next].free_idx], idx, .Release)
+ sync.atomic_store_explicit(&alloc.free_idx, _local_region.memory[old_next].free_idx, .Release)
} else {
// NOTE: We have aleady merged with prev, and now merged with next.
// Now, we are actually going to remove from the free_list.
@@ -492,10 +499,11 @@ _region_local_free :: proc(alloc: ^Allocation_Header) #no_bounds_check {
// This is the only place where anything is appended to the free list.
if add_to_free_list {
fl := _local_region.hdr.free_list
- alloc.free_idx = _local_region.hdr.free_list_len
- fl[alloc.free_idx] = alloc.idx
- _local_region.hdr.free_list_len += 1
- if int(_local_region.hdr.free_list_len) == len(fl) {
+ fl_len := sync.atomic_load(&_local_region.hdr.free_list_len)
+ sync.atomic_store_explicit(&alloc.free_idx, fl_len, .Release)
+ fl[alloc.free_idx] = idx
+ sync.atomic_store_explicit(&_local_region.hdr.free_list_len, fl_len + 1, .Release)
+ if int(fl_len + 1) == len(fl) {
free_alloc := _get_allocation_header(mem.raw_data(_local_region.hdr.free_list))
_region_resize(free_alloc, len(fl) * 2 * size_of(fl[0]), true)
}
@@ -512,8 +520,8 @@ _region_assign_free_list :: proc(region: ^Region, memory: rawptr, blocks: u16) {
_region_retrieve_with_space :: proc(blocks: u16, local_idx: int = -1, back_idx: int = -1) -> (^Region, int) {
r: ^Region
idx: int
- for r = global_regions; r != nil; r = r.hdr.next_region {
- if idx == local_idx || idx < back_idx || r.hdr.free_blocks < blocks {
+ for r = sync.atomic_load(&global_regions); r != nil; r = r.hdr.next_region {
+ if idx == local_idx || idx < back_idx || sync.atomic_load(&r.hdr.free_blocks) < blocks {
idx += 1
continue
}
@@ -581,7 +589,7 @@ _region_segment :: proc(region: ^Region, alloc: ^Allocation_Header, blocks, new_
_region_get_local_idx :: proc() -> int {
idx: int
- for r := global_regions; r != nil; r = r.hdr.next_region {
+ for r := sync.atomic_load(&global_regions); r != nil; r = r.hdr.next_region {
if r == _local_region {
return idx
}
@@ -597,9 +605,10 @@ _region_find_and_assign_local :: proc(alloc: ^Allocation_Header) {
_local_region = _region_retrieve_from_addr(alloc)
}
- // At this point, _local_region is set correctly. Spin until acquired
- res: ^^Region
- for res != &_local_region {
+ // At this point, _local_region is set correctly. Spin until acquire
+ res := CURRENTLY_ACTIVE
+
+ for res == CURRENTLY_ACTIVE {
res = sync.atomic_compare_exchange_strong_explicit(
&_local_region.hdr.local_addr,
&_local_region,
@@ -621,9 +630,9 @@ _region_contains_mem :: proc(r: ^Region, memory: rawptr) -> bool #no_bounds_chec
_region_free_list_remove :: proc(region: ^Region, free_idx: u16) #no_bounds_check {
// pop, swap and update allocation hdr
if n := region.hdr.free_list_len - 1; free_idx != n {
- region.hdr.free_list[free_idx] = region.hdr.free_list[n]
+ region.hdr.free_list[free_idx] = sync.atomic_load(&region.hdr.free_list[n])
alloc_idx := region.hdr.free_list[free_idx]
- region.memory[alloc_idx].free_idx = free_idx
+ sync.atomic_store_explicit(&region.memory[alloc_idx].free_idx, free_idx, .Release)
}
region.hdr.free_list_len -= 1
}
@@ -714,3 +723,4 @@ _get_allocation_header :: #force_inline proc(raw_mem: rawptr) -> ^Allocation_Hea
_round_up_to_nearest :: #force_inline proc(size, round: int) -> int {
return (size-1) + round - (size-1) % round
}
+
diff --git a/core/os/os2/heap_posix.odin b/core/os/os2/heap_posix.odin
index fcae267fa..1b52aed75 100644
--- a/core/os/os2/heap_posix.odin
+++ b/core/os/os2/heap_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
diff --git a/core/os/os2/heap_windows.odin b/core/os/os2/heap_windows.odin
index 4afc016a0..7fd4529a0 100644
--- a/core/os/os2/heap_windows.odin
+++ b/core/os/os2/heap_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:mem"
diff --git a/core/os/os2/internal_util.odin b/core/os/os2/internal_util.odin
index 041cd531b..164e1e1be 100644
--- a/core/os/os2/internal_util.odin
+++ b/core/os/os2/internal_util.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:intrinsics"
diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin
index ba2f7235c..7be4121ae 100644
--- a/core/os/os2/path_linux.odin
+++ b/core/os/os2/path_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:strings"
diff --git a/core/os/os2/path_posix.odin b/core/os/os2/path_posix.odin
index 39ada264e..6f358c58d 100644
--- a/core/os/os2/path_posix.odin
+++ b/core/os/os2/path_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
@@ -39,12 +39,12 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
return internal_mkdir_all(clean_path, perm)
internal_mkdir_all :: proc(path: string, perm: int) -> Error {
- a, _ := filepath.split(path)
- if a != path {
- if len(a) > 1 && a[len(a)-1] == '/' {
- a = a[:len(a)-1]
+ dir, file := filepath.split(path)
+ if file != path {
+ if len(dir) > 1 && dir[len(dir) - 1] == '/' {
+ dir = dir[:len(dir) - 1]
}
- internal_mkdir_all(a, perm) or_return
+ internal_mkdir_all(dir, perm) or_return
}
err := _mkdir(path, perm)
diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin
index 4aa695ee2..3e92cb6f3 100644
--- a/core/os/os2/path_windows.odin
+++ b/core/os/os2/path_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import win32 "core:sys/windows"
diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin
index 42315cf4e..ac3382bc3 100644
--- a/core/os/os2/pipe_linux.odin
+++ b/core/os/os2/pipe_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:sys/linux"
diff --git a/core/os/os2/pipe_posix.odin b/core/os/os2/pipe_posix.odin
index 13c1f8aec..487e32aea 100644
--- a/core/os/os2/pipe_posix.odin
+++ b/core/os/os2/pipe_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "core:sys/posix"
diff --git a/core/os/os2/pipe_windows.odin b/core/os/os2/pipe_windows.odin
index 59615e306..ee93fb683 100644
--- a/core/os/os2/pipe_windows.odin
+++ b/core/os/os2/pipe_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import win32 "core:sys/windows"
diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin
index f7a542276..ce65987b0 100644
--- a/core/os/os2/process.odin
+++ b/core/os/os2/process.odin
@@ -166,15 +166,15 @@ Process_Info :: struct {
This procedure obtains an information, specified by `selection` parameter of
a process given by `pid`.
-
- Use `free_process_info` to free the memory allocated by this procedure. In
- case the function returns an error it may only have been an error for one part
- of the information and you would still need to call it to free the other parts.
+
+ Use `free_process_info` to free the memory allocated by this procedure. The
+ `free_process_info` procedure needs to be called, even if this procedure
+ returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code
- returned by this function.
+ returned by this procedure.
*/
@(require_results)
process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -188,14 +188,14 @@ process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator:
about a process that has been opened by the application, specified in
the `process` parameter.
- Use `free_process_info` to free the memory allocated by this procedure. In
- case the function returns an error it may only have been an error for one part
- of the information and you would still need to call it to free the other parts.
+ Use `free_process_info` to free the memory allocated by this procedure. The
+ `free_process_info` procedure needs to be called, even if this procedure
+ returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code
- returned by this function.
+ returned by this procedure.
*/
@(require_results)
process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -208,14 +208,14 @@ process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields,
This procedure obtains the information, specified by `selection` parameter
about the currently running process.
- Use `free_process_info` to free the memory allocated by this procedure. In
- case the function returns an error it may only have been an error for one part
- of the information and you would still need to call it to free the other parts.
+ Use `free_process_info` to free the memory allocated by this procedure. The
+ `free_process_info` procedure needs to be called, even if this procedure
+ returned an error, as some of the fields may have been allocated.
**Note**: The resulting information may or may contain the fields specified
by the `selection` parameter. Always check whether the returned
`Process_Info` struct has the required fields before checking the error code
- returned by this function.
+ returned by this procedure.
*/
@(require_results)
current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (Process_Info, Error) {
@@ -305,6 +305,7 @@ Process_Desc :: struct {
// A slice of strings, each having the format `KEY=VALUE` representing the
// full environment that the child process will receive.
// In case this slice is `nil`, the current process' environment is used.
+ // NOTE(laytan): maybe should be `Maybe([]string)` so you can do `nil` == current env, empty == empty/no env.
env: []string,
// The `stderr` handle to give to the child process. It can be either a file
// or a writeable end of a pipe. Passing `nil` will shut down the process'
diff --git a/core/os/os2/process_linux.odin b/core/os/os2/process_linux.odin
index 40406bad5..ea5ee41b1 100644
--- a/core/os/os2/process_linux.odin
+++ b/core/os/os2/process_linux.odin
@@ -1,5 +1,5 @@
-//+build linux
-//+private file
+#+build linux
+#+private file
package os2
import "base:runtime"
@@ -490,7 +490,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
if errno = linux.pipe2(&child_pipe_fds, {.CLOEXEC}); errno != .NONE {
return process, _get_platform_error(errno)
}
- defer linux.close(child_pipe_fds[WRITE])
defer linux.close(child_pipe_fds[READ])
@@ -508,6 +507,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
//
pid: linux.Pid
if pid, errno = linux.fork(); errno != .NONE {
+ linux.close(child_pipe_fds[WRITE])
return process, _get_platform_error(errno)
}
@@ -573,25 +573,19 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
}
- success_byte: [1]u8
- linux.write(child_pipe_fds[WRITE], success_byte[:])
-
errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH})
-
- // NOTE: we can't tell the parent about this failure because we already wrote the success byte.
- // So if this happens the user will just see the process failed when they call process_wait.
-
assert(errno != nil)
- intrinsics.trap()
+ write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
}
+ linux.close(child_pipe_fds[WRITE])
+
process.pid = int(pid)
- n: int
child_byte: [1]u8
errno = .EINTR
for errno == .EINTR {
- n, errno = linux.read(child_pipe_fds[READ], child_byte[:])
+ _, errno = linux.read(child_pipe_fds[READ], child_byte[:])
}
// If the read failed, something weird happened. Do not return the read
diff --git a/core/os/os2/process_posix.odin b/core/os/os2/process_posix.odin
index c9b67f199..5ac6babc1 100644
--- a/core/os/os2/process_posix.odin
+++ b/core/os/os2/process_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
@@ -139,20 +139,22 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
err = _get_platform_error()
return
}
- defer posix.close(pipe[WRITE])
defer posix.close(pipe[READ])
if posix.fcntl(pipe[READ], .SETFD, i32(posix.FD_CLOEXEC)) == -1 {
+ posix.close(pipe[WRITE])
err = _get_platform_error()
return
}
if posix.fcntl(pipe[WRITE], .SETFD, i32(posix.FD_CLOEXEC)) == -1 {
+ posix.close(pipe[WRITE])
err = _get_platform_error()
return
}
switch pid := posix.fork(); pid {
case -1:
+ posix.close(pipe[WRITE])
err = _get_platform_error()
return
@@ -179,25 +181,20 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
if posix.chdir(cwd) != .OK { abort(pipe[WRITE]) }
}
- ok := u8(0)
- posix.write(pipe[WRITE], &ok, 1)
-
res := posix.execve(strings.to_cstring(&exe_builder), raw_data(cmd), env)
-
- // NOTE: we can't tell the parent about this failure because we already wrote the success byte.
- // So if this happens the user will just see the process failed when they call process_wait.
-
assert(res == -1)
- runtime.trap()
+ abort(pipe[WRITE])
case:
+ posix.close(pipe[WRITE])
+
errno: posix.Errno
for {
errno_byte: u8
switch posix.read(pipe[READ], &errno_byte, 1) {
- case 1:
+ case 1:
errno = posix.Errno(errno_byte)
- case:
+ case -1:
errno = posix.errno()
if errno == .EINTR {
continue
diff --git a/core/os/os2/process_posix_darwin.odin b/core/os/os2/process_posix_darwin.odin
index 648c4d389..0ea1f643c 100644
--- a/core/os/os2/process_posix_darwin.odin
+++ b/core/os/os2/process_posix_darwin.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/process_posix_other.odin b/core/os/os2/process_posix_other.odin
index 02f78b9ac..77dbfa7eb 100644
--- a/core/os/os2/process_posix_other.odin
+++ b/core/os/os2/process_posix_other.odin
@@ -1,5 +1,5 @@
-//+private
-//+build netbsd, openbsd, freebsd
+#+private
+#+build netbsd, openbsd, freebsd
package os2
import "base:runtime"
diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin
index 47fd62401..0c32373f3 100644
--- a/core/os/os2/process_windows.odin
+++ b/core/os/os2/process_windows.odin
@@ -1,4 +1,4 @@
-//+private file
+#+private file
package os2
import "base:runtime"
@@ -93,16 +93,33 @@ read_memory_as_slice :: proc(h: win32.HANDLE, addr: rawptr, dest: []$T) -> (byte
@(private="package")
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
info.pid = pid
- defer if err != nil {
- free_process_info(info, allocator)
+ // Note(flysand): Open the process handle right away to prevent some race
+ // conditions. Once the handle is open, the process will be kept alive by
+ // the OS.
+ ph := win32.INVALID_HANDLE_VALUE
+ if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} {
+ ph = win32.OpenProcess(
+ win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ,
+ false,
+ u32(pid),
+ )
+ if ph == win32.INVALID_HANDLE_VALUE {
+ err = _get_platform_error()
+ return
+ }
}
-
- // Data obtained from process snapshots
- if selection >= {.PPid, .Priority} {
+ defer if ph != win32.INVALID_HANDLE_VALUE {
+ win32.CloseHandle(ph)
+ }
+ snapshot_process: if selection >= {.PPid, .Priority} {
entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil {
- err = General_Error.Not_Exist
- return
+ err = entry_err
+ if entry_err == General_Error.Not_Exist {
+ return
+ } else {
+ break snapshot_process
+ }
}
if .PPid in selection {
info.fields += {.PPid}
@@ -113,29 +130,18 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
info.priority = int(entry.pcPriClassBase)
}
}
- if .Executable_Path in selection { // snap module
- info.executable_path = _process_exe_by_pid(pid, allocator) or_return
- info.fields += {.Executable_Path}
- }
-
- ph := win32.INVALID_HANDLE_VALUE
-
- if selection >= {.Command_Line, .Environment, .Working_Dir, .Username} { // need process handle
- ph = win32.OpenProcess(
- win32.PROCESS_QUERY_LIMITED_INFORMATION | win32.PROCESS_VM_READ,
- false,
- u32(pid),
- )
- if ph == win32.INVALID_HANDLE_VALUE {
- err = _get_platform_error()
+ snapshot_modules: if .Executable_Path in selection {
+ exe_path: string
+ exe_path, err = _process_exe_by_pid(pid, allocator)
+ if _, ok := err.(runtime.Allocator_Error); ok {
return
+ } else if err != nil {
+ break snapshot_modules
}
+ info.executable_path = exe_path
+ info.fields += {.Executable_Path}
}
- defer if ph != win32.INVALID_HANDLE_VALUE {
- win32.CloseHandle(ph)
- }
-
- if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
+ read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
process_info_size: u32
process_info: win32.PROCESS_BASIC_INFORMATION
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
@@ -143,25 +149,26 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
// TODO(flysand): There's probably a mismatch between NTSTATUS and
// windows userland error codes, I haven't checked.
err = Platform_Error(status)
- return
- }
- if process_info.PebBaseAddress == nil {
- // Not sure what the error is
- err = General_Error.Unsupported
- return
+ break read_peb
}
+ assert(process_info.PebBaseAddress != nil)
process_peb: win32.PEB
-
- _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return
-
+ _, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
+ if err != nil {
+ break read_peb
+ }
process_params: win32.RTL_USER_PROCESS_PARAMETERS
- _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return
-
+ _, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
+ if err != nil {
+ break read_peb
+ }
if selection >= {.Command_Line, .Command_Args} {
TEMP_ALLOCATOR_GUARD()
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
+ if err != nil {
+ break read_peb
+ }
if .Command_Line in selection {
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
info.fields += {.Command_Line}
@@ -175,23 +182,33 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
TEMP_ALLOCATOR_GUARD()
env_len := process_params.EnvironmentSize / 2
envs_w := make([]u16, env_len, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
+ if err != nil {
+ break read_peb
+ }
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
info.fields += {.Environment}
}
if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
+ if err != nil {
+ break read_peb
+ }
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
info.fields += {.Working_Dir}
}
}
-
- if .Username in selection {
- info.username = _get_process_user(ph, allocator) or_return
+ read_username: if .Username in selection {
+ username: string
+ username, err = _get_process_user(ph, allocator)
+ if _, ok := err.(runtime.Allocator_Error); ok {
+ return
+ } else if err != nil {
+ break read_username
+ }
+ info.username = username
info.fields += {.Username}
}
err = nil
@@ -202,16 +219,16 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
_process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
pid := process.pid
info.pid = pid
- defer if err != nil {
- free_process_info(info, allocator)
- }
-
// Data obtained from process snapshots
- if selection >= {.PPid, .Priority} { // snap process
+ snapshot_process: if selection >= {.PPid, .Priority} {
entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil {
- err = General_Error.Not_Exist
- return
+ err = entry_err
+ if entry_err == General_Error.Not_Exist {
+ return
+ } else {
+ break snapshot_process
+ }
}
if .PPid in selection {
info.fields += {.PPid}
@@ -222,12 +239,19 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.priority = int(entry.pcPriClassBase)
}
}
- if .Executable_Path in selection { // snap module
- info.executable_path = _process_exe_by_pid(pid, allocator) or_return
+ snapshot_module: if .Executable_Path in selection {
+ exe_path: string
+ exe_path, err = _process_exe_by_pid(pid, allocator)
+ if _, ok := err.(runtime.Allocator_Error); ok {
+ return
+ } else if err != nil {
+ break snapshot_module
+ }
+ info.executable_path = exe_path
info.fields += {.Executable_Path}
}
ph := win32.HANDLE(process.handle)
- if selection >= {.Command_Line, .Environment, .Working_Dir} { // need peb
+ read_peb: if selection >= {.Command_Line, .Environment, .Working_Dir} {
process_info_size: u32
process_info: win32.PROCESS_BASIC_INFORMATION
status := win32.NtQueryInformationProcess(ph, .ProcessBasicInformation, &process_info, size_of(process_info), &process_info_size)
@@ -237,23 +261,24 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
err = Platform_Error(status)
return
}
- if process_info.PebBaseAddress == nil {
- // Not sure what the error is
- err = General_Error.Unsupported
- return
- }
-
+ assert(process_info.PebBaseAddress != nil)
process_peb: win32.PEB
- _ = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb) or_return
-
+ _, err = read_memory_as_struct(ph, process_info.PebBaseAddress, &process_peb)
+ if err != nil {
+ break read_peb
+ }
process_params: win32.RTL_USER_PROCESS_PARAMETERS
- _ = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params) or_return
-
+ _, err = read_memory_as_struct(ph, process_peb.ProcessParameters, &process_params)
+ if err != nil {
+ break read_peb
+ }
if selection >= {.Command_Line, .Command_Args} {
TEMP_ALLOCATOR_GUARD()
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
+ if err != nil {
+ break read_peb
+ }
if .Command_Line in selection {
info.command_line = win32_utf16_to_utf8(cmdline_w, allocator) or_return
info.fields += {.Command_Line}
@@ -263,28 +288,37 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields += {.Command_Args}
}
}
-
if .Environment in selection {
TEMP_ALLOCATOR_GUARD()
env_len := process_params.EnvironmentSize / 2
envs_w := make([]u16, env_len, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.Environment, envs_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
+ if err != nil {
+ break read_peb
+ }
info.environment = _parse_environment_block(raw_data(envs_w), allocator) or_return
info.fields += {.Environment}
}
-
if .Working_Dir in selection {
TEMP_ALLOCATOR_GUARD()
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
- _ = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) or_return
-
+ _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
+ if err != nil {
+ break read_peb
+ }
info.working_dir = win32_utf16_to_utf8(cwd_w, allocator) or_return
info.fields += {.Working_Dir}
}
}
- if .Username in selection {
- info.username = _get_process_user(ph, allocator) or_return
+ read_username: if .Username in selection {
+ username: string
+ username, err = _get_process_user(ph, allocator)
+ if _, ok := err.(runtime.Allocator_Error); ok {
+ return
+ } else if err != nil {
+ break read_username
+ }
+ info.username = username
info.fields += {.Username}
}
err = nil
@@ -294,15 +328,15 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
@(private="package")
_current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
info.pid = get_pid()
- defer if err != nil {
- free_process_info(info, allocator)
- }
-
- if selection >= {.PPid, .Priority} { // snap process
+ snapshot_process: if selection >= {.PPid, .Priority} {
entry, entry_err := _process_entry_by_pid(info.pid)
if entry_err != nil {
- err = General_Error.Not_Exist
- return
+ err = entry_err
+ if entry_err == General_Error.Not_Exist {
+ return
+ } else {
+ break snapshot_process
+ }
}
if .PPid in selection {
info.fields += {.PPid}
@@ -313,14 +347,16 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
info.priority = int(entry.pcPriClassBase)
}
}
- if .Executable_Path in selection {
+ module_filename: if .Executable_Path in selection {
exe_filename_w: [256]u16
path_len := win32.GetModuleFileNameW(nil, raw_data(exe_filename_w[:]), len(exe_filename_w))
+ assert(path_len > 0)
info.executable_path = win32_utf16_to_utf8(exe_filename_w[:path_len], allocator) or_return
info.fields += {.Executable_Path}
}
- if selection >= {.Command_Line, .Command_Args} {
+ command_line: if selection >= {.Command_Line, .Command_Args} {
command_line_w := win32.GetCommandLineW()
+ assert(command_line_w != nil)
if .Command_Line in selection {
info.command_line = win32_wstring_to_utf8(command_line_w, allocator) or_return
info.fields += {.Command_Line}
@@ -330,14 +366,22 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime
info.fields += {.Command_Args}
}
}
- if .Environment in selection {
+ read_environment: if .Environment in selection {
env_block := win32.GetEnvironmentStringsW()
+ assert(env_block != nil)
info.environment = _parse_environment_block(env_block, allocator) or_return
info.fields += {.Environment}
}
- if .Username in selection {
+ read_username: if .Username in selection {
process_handle := win32.GetCurrentProcess()
- info.username = _get_process_user(process_handle, allocator) or_return
+ username: string
+ username, err = _get_process_user(process_handle, allocator)
+ if _, ok := err.(runtime.Allocator_Error); ok {
+ return
+ } else if err != nil {
+ break read_username
+ }
+ info.username = username
info.fields += {.Username}
}
if .Working_Dir in selection {
diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin
index 6ccac1be0..0433c1a61 100644
--- a/core/os/os2/stat_linux.odin
+++ b/core/os/os2/stat_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "core:time"
diff --git a/core/os/os2/stat_posix.odin b/core/os/os2/stat_posix.odin
index a817a862b..88029c1f5 100644
--- a/core/os/os2/stat_posix.odin
+++ b/core/os/os2/stat_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin
index 566417c84..8ed2a6fed 100644
--- a/core/os/os2/stat_windows.odin
+++ b/core/os/os2/stat_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/temp_file_linux.odin b/core/os/os2/temp_file_linux.odin
index d6f90fbaf..4eacbc54a 100644
--- a/core/os/os2/temp_file_linux.odin
+++ b/core/os/os2/temp_file_linux.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/temp_file_posix.odin b/core/os/os2/temp_file_posix.odin
index 67ec4d3e8..b44ea13a7 100644
--- a/core/os/os2/temp_file_posix.odin
+++ b/core/os/os2/temp_file_posix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, netbsd, freebsd, openbsd
+#+private
+#+build darwin, netbsd, freebsd, openbsd
package os2
import "base:runtime"
diff --git a/core/os/os2/temp_file_windows.odin b/core/os/os2/temp_file_windows.odin
index d888eda52..3e3e1285c 100644
--- a/core/os/os2/temp_file_windows.odin
+++ b/core/os/os2/temp_file_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package os2
import "base:runtime"
diff --git a/core/os/os2/user.odin b/core/os/os2/user.odin
index af0bc5da4..a0a7a839d 100644
--- a/core/os/os2/user.odin
+++ b/core/os/os2/user.odin
@@ -4,21 +4,23 @@ import "base:runtime"
@(require_results)
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
+ TEMP_ALLOCATOR_GUARD()
+
#partial switch ODIN_OS {
case .Windows:
- dir = get_env("LocalAppData", allocator)
+ dir = get_env("LocalAppData", temp_allocator())
if dir != "" {
dir = clone_string(dir, allocator) or_return
}
case .Darwin:
- dir = get_env("HOME", allocator)
+ dir = get_env("HOME", temp_allocator())
if dir != "" {
dir = concatenate({dir, "/Library/Caches"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
- dir = get_env("HOME", allocator)
+ dir = get_env("HOME", temp_allocator())
if dir == "" {
return
}
@@ -33,21 +35,23 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
@(require_results)
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
+ TEMP_ALLOCATOR_GUARD()
+
#partial switch ODIN_OS {
case .Windows:
- dir = get_env("AppData", allocator)
+ dir = get_env("AppData", temp_allocator())
if dir != "" {
dir = clone_string(dir, allocator) or_return
}
case .Darwin:
- dir = get_env("HOME", allocator)
+ dir = get_env("HOME", temp_allocator())
if dir != "" {
dir = concatenate({dir, "/.config"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
- dir = get_env("HOME", allocator)
+ dir = get_env("HOME", temp_allocator())
if dir == "" {
return
}
diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin
index f694dd588..371485a47 100644
--- a/core/os/os_darwin.odin
+++ b/core/os/os_darwin.odin
@@ -206,7 +206,7 @@ ENOPROTOOPT :: _Platform_Error.ENOPROTOOPT
EPROTONOSUPPORT :: _Platform_Error.EPROTONOSUPPORT
ESOCKTNOSUPPORT :: _Platform_Error.ESOCKTNOSUPPORT
ENOTSUP :: _Platform_Error.ENOTSUP
-EOPNOTSUPP :: _Platform_Error.EOPNOTSUPP
+EOPNOTSUPP :: _Platform_Error.EOPNOTSUPP
EPFNOSUPPORT :: _Platform_Error.EPFNOSUPPORT
EAFNOSUPPORT :: _Platform_Error.EAFNOSUPPORT
EADDRINUSE :: _Platform_Error.EADDRINUSE
@@ -812,10 +812,21 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
assert(fd != -1)
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
final_offset := i64(_unix_lseek(fd, int(offset), c.int(whence)))
if final_offset == -1 {
- return 0, get_last_error()
+ errno := get_last_error()
+ switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ }
+ return 0, errno
}
return final_offset, nil
}
@@ -1119,7 +1130,8 @@ unset_env :: proc(key: string) -> Error {
}
@(require_results)
-get_current_directory :: proc() -> string {
+get_current_directory :: proc(allocator := context.allocator) -> string {
+ context.allocator = allocator
page_size := get_page_size() // NOTE(tetra): See note in os_linux.odin/get_current_directory.
buf := make([dynamic]u8, page_size)
for {
diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin
index 41c487b2b..f617cf973 100644
--- a/core/os/os_freebsd.odin
+++ b/core/os/os_freebsd.odin
@@ -6,6 +6,7 @@ foreign import libc "system:c"
import "base:runtime"
import "core:strings"
import "core:c"
+import "core:sys/freebsd"
Handle :: distinct i32
File_Time :: distinct u64
@@ -446,8 +447,7 @@ close :: proc(fd: Handle) -> Error {
}
flush :: proc(fd: Handle) -> Error {
- // do nothing
- return nil
+ return cast(_Platform_Error)freebsd.fsync(cast(freebsd.Fd)fd)
}
// If you read or write more than `INT_MAX` bytes, FreeBSD returns `EINVAL`.
@@ -481,29 +481,45 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) {
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = read(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_read := min(uint(len(data)), MAX_RW)
+
+ bytes_read, errno := freebsd.pread(cast(freebsd.Fd)fd, data[:to_read], cast(freebsd.off_t)offset)
+
+ return bytes_read, cast(_Platform_Error)errno
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = write(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_write := min(uint(len(data)), MAX_RW)
+
+ bytes_written, errno := freebsd.pwrite(cast(freebsd.Fd)fd, data[:to_write], cast(freebsd.off_t)offset)
+
+ return bytes_written, cast(_Platform_Error)errno
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
- return -1, get_last_error()
+ errno := get_last_error()
+ switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ case:
+ return 0, errno
+ }
}
return res, nil
}
@@ -824,7 +840,8 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string)
}
@(require_results)
-get_current_directory :: proc() -> string {
+get_current_directory :: proc(allocator := context.allocator) -> string {
+ context.allocator = allocator
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
// an authoritative value for it across all systems.
// The largest value I could find was 4096, so might as well use the page size.
@@ -904,7 +921,7 @@ get_page_size :: proc() -> int {
_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
- if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
+ if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
diff --git a/core/os/os_freestanding.odin b/core/os/os_freestanding.odin
index c908e3738..c22a6d7d5 100644
--- a/core/os/os_freestanding.odin
+++ b/core/os/os_freestanding.odin
@@ -1,4 +1,4 @@
-//+build freestanding
+#+build freestanding
package os
#panic("package os does not support a freestanding target")
diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin
index 2d87c07a6..0d2c334be 100644
--- a/core/os/os_haiku.odin
+++ b/core/os/os_haiku.odin
@@ -119,49 +119,52 @@ S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK
foreign libc {
- @(link_name="_errorp") __error :: proc() -> ^c.int ---
-
- @(link_name="fork") _unix_fork :: proc() -> pid_t ---
- @(link_name="getthrid") _unix_getthrid :: proc() -> int ---
-
- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u16) -> Handle ---
- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
- @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
- @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
- @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
- @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
- @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
- @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
- @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
- @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
- @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
- @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
- @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
- @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
-
- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
- @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
- @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
-
- @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
- @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
- @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
-
- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
-
- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
-
- @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
- @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
- @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
- @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
+ @(link_name="_errorp") __error :: proc() -> ^c.int ---
+
+ @(link_name="fork") _unix_fork :: proc() -> pid_t ---
+ @(link_name="getthrid") _unix_getthrid :: proc() -> int ---
+
+ @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u16) -> Handle ---
+ @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
+ @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pread") _unix_pread :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
+ @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pwrite") _unix_pwrite :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
+ @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
+ @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
+ @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
+ @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
+ @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
+ @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
+ @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
+ @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
+ @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
+ @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
+ @(link_name="fsync") _unix_fsync :: proc(fd: Handle) -> c.int ---
+
+ @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
+ @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
+ @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
+ @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
+ @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
+ @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
+
+ @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
+ @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
+ @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
+ @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
+
+ @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
+ @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
+
+ @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
+
+ @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
+ @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
+ @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
+ @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
}
MAXNAMLEN :: haiku.NAME_MAX
@@ -216,7 +219,10 @@ close :: proc(fd: Handle) -> Error {
}
flush :: proc(fd: Handle) -> Error {
- // do nothing
+ result := _unix_fsync(fd)
+ if result == -1 {
+ return get_last_error()
+ }
return nil
}
@@ -250,29 +256,48 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) {
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = read(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_read := min(uint(len(data)), MAX_RW)
+
+ bytes_read := _unix_pread(fd, raw_data(data), to_read, offset)
+ if bytes_read < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_read, nil
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = write(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_write := min(uint(len(data)), MAX_RW)
+
+ bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset)
+ if bytes_written < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_written, nil
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
- return -1, get_last_error()
+ errno := get_last_error()
+ switch errno {
+ case .BAD_VALUE:
+ return 0, .Invalid_Offset
+ }
+ return 0, errno
}
return res, nil
}
diff --git a/core/os/os_js.odin b/core/os/os_js.odin
index eb434c727..348554728 100644
--- a/core/os/os_js.odin
+++ b/core/os/os_js.odin
@@ -1,35 +1,38 @@
-//+build js
+#+build js
package os
-import "base:runtime"
+foreign import "odin_env"
@(require_results)
is_path_separator :: proc(c: byte) -> bool {
return c == '/' || c == '\\'
}
+Handle :: distinct u32
+
+stdout: Handle = 1
+stderr: Handle = 2
+
@(require_results)
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) {
unimplemented("core:os procedure not supported on JS target")
}
close :: proc(fd: Handle) -> Error {
- unimplemented("core:os procedure not supported on JS target")
+ return nil
}
flush :: proc(fd: Handle) -> (err: Error) {
- unimplemented("core:os procedure not supported on JS target")
+ return nil
}
-
-
write :: proc(fd: Handle, data: []byte) -> (int, Error) {
- unimplemented("core:os procedure not supported on JS target")
-}
-
-@(private="file")
-read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Error) {
- unimplemented("core:os procedure not supported on JS target")
+ foreign odin_env {
+ @(link_name="write")
+ _write :: proc "contextless" (fd: Handle, p: []byte) ---
+ }
+ _write(fd, data)
+ return len(data), nil
}
read :: proc(fd: Handle, data: []byte) -> (int, Error) {
@@ -45,19 +48,6 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
unimplemented("core:os procedure not supported on JS target")
}
-
-@(private)
-MAX_RW :: 1<<30
-
-@(private)
-pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
- unimplemented("core:os procedure not supported on JS target")
-}
-@(private)
-pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
- unimplemented("core:os procedure not supported on JS target")
-}
-
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
@@ -65,16 +55,6 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error)
unimplemented("core:os procedure not supported on JS target")
}
-stdout: Handle = 1
-stderr: Handle = 2
-
-@(require_results)
-get_std_handle :: proc "contextless" (h: uint) -> Handle {
- context = runtime.default_context()
- unimplemented("core:os procedure not supported on JS target")
-}
-
-
@(require_results)
exists :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
@@ -90,9 +70,6 @@ is_dir :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
}
-// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
-//@private cwd_lock := win32.SRWLOCK{} // zero is initialized
-
@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
unimplemented("core:os procedure not supported on JS target")
@@ -118,18 +95,6 @@ remove_directory :: proc(path: string) -> (err: Error) {
}
-
-@(private, require_results)
-is_abs :: proc(path: string) -> bool {
- unimplemented("core:os procedure not supported on JS target")
-}
-
-@(private, require_results)
-fix_long_path :: proc(path: string) -> string {
- unimplemented("core:os procedure not supported on JS target")
-}
-
-
link :: proc(old_name, new_name: string) -> (err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
@@ -169,7 +134,6 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
unimplemented("core:os procedure not supported on JS target")
}
-Handle :: distinct uintptr
File_Time :: distinct u64
_Platform_Error :: enum i32 {
@@ -254,12 +218,7 @@ WSAECONNRESET :: Platform_Error.WSAECONNRESET
ERROR_FILE_IS_PIPE :: General_Error.File_Is_Pipe
ERROR_FILE_IS_NOT_DIR :: General_Error.Not_Dir
-// "Argv" arguments converted to Odin strings
-args := _alloc_command_line_arguments()
-
-
-
-
+args: []string
@(require_results)
last_write_time :: proc(fd: Handle) -> (File_Time, Error) {
@@ -279,26 +238,14 @@ get_page_size :: proc() -> int {
@(private, require_results)
_processor_core_count :: proc() -> int {
- unimplemented("core:os procedure not supported on JS target")
+ return 1
}
exit :: proc "contextless" (code: int) -> ! {
- context = runtime.default_context()
- unimplemented("core:os procedure not supported on JS target")
+ unimplemented_contextless("core:os procedure not supported on JS target")
}
-
-
@(require_results)
current_thread_id :: proc "contextless" () -> int {
- context = runtime.default_context()
- unimplemented("core:os procedure not supported on JS target")
+ return 0
}
-
-
-
-@(require_results)
-_alloc_command_line_arguments :: proc() -> []string {
- return nil
-}
-
diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin
index 2f7a5ac43..8c8cd7f73 100644
--- a/core/os/os_linux.odin
+++ b/core/os/os_linux.odin
@@ -395,9 +395,9 @@ SIOCGIFFLAG :: enum c.int {
PORTSEL = 13, /* Can set media type. */
AUTOMEDIA = 14, /* Auto media select active. */
DYNAMIC = 15, /* Dialup device with changing addresses. */
- LOWER_UP = 16,
- DORMANT = 17,
- ECHO = 18,
+ LOWER_UP = 16,
+ DORMANT = 17,
+ ECHO = 18,
}
SIOCGIFFLAGS :: bit_set[SIOCGIFFLAG; c.int]
@@ -584,8 +584,7 @@ close :: proc(fd: Handle) -> Error {
}
flush :: proc(fd: Handle) -> Error {
- // do nothing
- return nil
+ return _get_errno(unix.sys_fsync(int(fd)))
}
// If you read or write more than `SSIZE_MAX` bytes, result is implementation defined (probably an error).
@@ -654,9 +653,20 @@ write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
res := unix.sys_lseek(int(fd), offset, whence)
if res < 0 {
- return -1, _get_errno(int(res))
+ errno := _get_errno(int(res))
+ switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ }
+ return 0, errno
}
return i64(res), nil
}
@@ -975,7 +985,8 @@ unset_env :: proc(key: string) -> Error {
}
@(require_results)
-get_current_directory :: proc() -> string {
+get_current_directory :: proc(allocator := context.allocator) -> string {
+ context.allocator = allocator
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
// an authoritative value for it across all systems.
// The largest value I could find was 4096, so might as well use the page size.
diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin
index 82a8dc1eb..493527803 100644
--- a/core/os/os_netbsd.odin
+++ b/core/os/os_netbsd.odin
@@ -426,7 +426,9 @@ foreign libc {
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u32) -> Handle ---
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pread") _unix_pread :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pwrite") _unix_pwrite :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
@@ -441,6 +443,7 @@ foreign libc {
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int ---
+ @(link_name="fsync") _unix_fsync :: proc(fd: Handle) -> c.int ---
@(link_name="dup") _unix_dup :: proc(fd: Handle) -> Handle ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@@ -504,7 +507,10 @@ close :: proc(fd: Handle) -> Error {
}
flush :: proc(fd: Handle) -> Error {
- // do nothing
+ result := _unix_fsync(fd)
+ if result == -1 {
+ return get_last_error()
+ }
return nil
}
@@ -535,29 +541,48 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) {
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = read(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_read := min(uint(len(data)), MAX_RW)
+
+ bytes_read := _unix_pread(fd, raw_data(data), to_read, offset)
+ if bytes_read < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_read, nil
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = write(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_write := min(uint(len(data)), MAX_RW)
+
+ bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset)
+ if bytes_written < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_written, nil
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
- return -1, get_last_error()
+ errno := get_last_error()
+ switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ }
+ return 0, errno
}
return res, nil
}
@@ -869,7 +894,8 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string)
}
@(require_results)
-get_current_directory :: proc() -> string {
+get_current_directory :: proc(allocator := context.allocator) -> string {
+ context.allocator = allocator
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
// an authoritative value for it across all systems.
// The largest value I could find was 4096, so might as well use the page size.
@@ -953,7 +979,7 @@ get_page_size :: proc() -> int {
_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
- if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
+ if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin
index 44eac8564..62872d9dc 100644
--- a/core/os/os_openbsd.odin
+++ b/core/os/os_openbsd.odin
@@ -343,50 +343,53 @@ AT_REMOVEDIR :: 0x08
@(default_calling_convention="c")
foreign libc {
- @(link_name="__error") __error :: proc() -> ^c.int ---
-
- @(link_name="fork") _unix_fork :: proc() -> pid_t ---
- @(link_name="getthrid") _unix_getthrid :: proc() -> int ---
-
- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u32) -> Handle ---
- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
- @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
- @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
- @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
- @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
- @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
- @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
- @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
- @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
- @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
- @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
- @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
- @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
- @(link_name="dup") _unix_dup :: proc(fd: Handle) -> Handle ---
-
- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
- @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
- @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
-
- @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
- @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
- @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
-
- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
-
- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
-
- @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
- @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
- @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
- @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
+ @(link_name="__error") __error :: proc() -> ^c.int ---
+
+ @(link_name="fork") _unix_fork :: proc() -> pid_t ---
+ @(link_name="getthrid") _unix_getthrid :: proc() -> int ---
+
+ @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u32) -> Handle ---
+ @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
+ @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pread") _unix_pread :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
+ @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="pwrite") _unix_pwrite :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
+ @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
+ @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
+ @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
+ @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
+ @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
+ @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
+ @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
+ @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
+ @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
+ @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
+ @(link_name="fsync") _unix_fsync :: proc(fd: Handle) -> c.int ---
+ @(link_name="dup") _unix_dup :: proc(fd: Handle) -> Handle ---
+
+ @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
+ @(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
+ @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
+ @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
+ @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
+ @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
+
+ @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
+ @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
+ @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
+ @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
+
+ @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
+ @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
+
+ @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
+
+ @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
+ @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
+ @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
+ @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
}
@(require_results)
@@ -428,7 +431,10 @@ close :: proc(fd: Handle) -> Error {
}
flush :: proc(fd: Handle) -> Error {
- // do nothing
+ result := _unix_fsync(fd)
+ if result == -1 {
+ return get_last_error()
+ }
return nil
}
@@ -463,29 +469,48 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) {
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = read(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_read := min(uint(len(data)), MAX_RW)
+
+ bytes_read := _unix_pread(fd, raw_data(data), to_read, offset)
+ if bytes_read < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_read, nil
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
- curr := seek(fd, offset, SEEK_CUR) or_return
- n, err = write(fd, data)
- _, err1 := seek(fd, curr, SEEK_SET)
- if err1 != nil && err == nil {
- err = err1
+ if len(data) == 0 {
+ return 0, nil
}
- return
+
+ to_write := min(uint(len(data)), MAX_RW)
+
+ bytes_written := _unix_pwrite(fd, raw_data(data), to_write, offset)
+ if bytes_written < 0 {
+ return -1, get_last_error()
+ }
+ return bytes_written, nil
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
+ switch whence {
+ case SEEK_SET, SEEK_CUR, SEEK_END:
+ break
+ case:
+ return 0, .Invalid_Whence
+ }
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
- return -1, get_last_error()
+ errno := get_last_error()
+ switch errno {
+ case .EINVAL:
+ return 0, .Invalid_Offset
+ }
+ return 0, errno
}
return res, nil
}
@@ -781,7 +806,8 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string)
}
@(require_results)
-get_current_directory :: proc() -> string {
+get_current_directory :: proc(allocator := context.allocator) -> string {
+ context.allocator = allocator
buf := make([dynamic]u8, MAX_PATH)
for {
cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf)))
diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin
index 273fe5af0..552508f3b 100644
--- a/core/os/os_windows.odin
+++ b/core/os/os_windows.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package os
import win32 "core:sys/windows"
@@ -43,6 +43,7 @@ ERROR_BUFFER_OVERFLOW :: _Platform_Error(111)
ERROR_INSUFFICIENT_BUFFER :: _Platform_Error(122)
ERROR_MOD_NOT_FOUND :: _Platform_Error(126)
ERROR_PROC_NOT_FOUND :: _Platform_Error(127)
+ERROR_NEGATIVE_SEEK :: _Platform_Error(131)
ERROR_DIR_NOT_EMPTY :: _Platform_Error(145)
ERROR_ALREADY_EXISTS :: _Platform_Error(183)
ERROR_ENVVAR_NOT_FOUND :: _Platform_Error(203)
@@ -91,6 +92,9 @@ get_last_error :: proc "contextless" () -> Error {
case win32.ERROR_INVALID_HANDLE:
return .Invalid_File
+ case win32.ERROR_NEGATIVE_SEEK:
+ return .Invalid_Offset
+
case
win32.ERROR_BAD_ARGUMENTS,
win32.ERROR_INVALID_PARAMETER,
diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin
index 8e89bee4f..7f7985e83 100644
--- a/core/os/stat_unix.odin
+++ b/core/os/stat_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
package os
import "core:time"
diff --git a/core/os/stream.odin b/core/os/stream.odin
index 8acbee489..39edc9cd5 100644
--- a/core/os/stream.odin
+++ b/core/os/stream.odin
@@ -21,6 +21,9 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
case .Flush:
os_err = flush(fd)
case .Read:
+ if len(p) == 0 {
+ return 0, nil
+ }
n_int, os_err = read(fd, p)
n = i64(n_int)
if n == 0 && os_err == nil {
@@ -28,18 +31,27 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
}
case .Read_At:
+ if len(p) == 0 {
+ return 0, nil
+ }
n_int, os_err = read_at(fd, p, offset)
n = i64(n_int)
if n == 0 && os_err == nil {
err = .EOF
}
case .Write:
+ if len(p) == 0 {
+ return 0, nil
+ }
n_int, os_err = write(fd, p)
n = i64(n_int)
if n == 0 && os_err == nil {
err = .EOF
}
case .Write_At:
+ if len(p) == 0 {
+ return 0, nil
+ }
n_int, os_err = write_at(fd, p, offset)
n = i64(n_int)
if n == 0 && os_err == nil {
@@ -58,5 +70,8 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
if err == nil && os_err != nil {
err = error_to_io_error(os_err)
}
+ if err != nil {
+ n = 0
+ }
return
}
diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin
index 7137ad844..a18dc739e 100644
--- a/core/path/filepath/path_unix.odin
+++ b/core/path/filepath/path_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd
+#+build linux, darwin, freebsd, openbsd, netbsd
package filepath
when ODIN_OS == .Darwin {
diff --git a/core/prof/spall/doc.odin b/core/prof/spall/doc.odin
index d9259465b..c81bad05f 100644
--- a/core/prof/spall/doc.odin
+++ b/core/prof/spall/doc.odin
@@ -1,4 +1,7 @@
/*
+Example:
+ package main
+
import "base:runtime"
import "core:prof/spall"
import "core:sync"
diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin
index b25d2b336..8060af448 100644
--- a/core/prof/spall/spall_linux.odin
+++ b/core/prof/spall/spall_linux.odin
@@ -1,10 +1,10 @@
-//+private
+#+private
package spall
// Only for types and constants.
import "core:os"
-// Package is `//+no-instrumentation`, safe to use.
+// Package is `#+no-instrumentation`, safe to use.
import "core:sys/linux"
MAX_RW :: 0x7fffffff
diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin
index fc05b8525..455245aad 100644
--- a/core/prof/spall/spall_unix.odin
+++ b/core/prof/spall/spall_unix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, freebsd, openbsd, netbsd
+#+private
+#+build darwin, freebsd, openbsd, netbsd
package spall
// Only for types.
diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin
index c8b044963..11e216b63 100644
--- a/core/prof/spall/spall_windows.odin
+++ b/core/prof/spall/spall_windows.odin
@@ -1,10 +1,10 @@
-//+private
+#+private
package spall
// Only for types.
import "core:os"
-// Package is `//+no-instrumentation`, safe to use.
+// Package is `#+no-instrumentation`, safe to use.
import win32 "core:sys/windows"
MAX_RW :: 1<<30
diff --git a/core/reflect/iterator.odin b/core/reflect/iterator.odin
index 5b84f0133..090fe04cc 100644
--- a/core/reflect/iterator.odin
+++ b/core/reflect/iterator.odin
@@ -19,6 +19,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(val.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id
ok = true
+ index = it^
it^ += 1
}
case Type_Info_Slice:
@@ -27,6 +28,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id
ok = true
+ index = it^
it^ += 1
}
case Type_Info_Dynamic_Array:
@@ -35,6 +37,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
elem.data = rawptr(uintptr(array.data) + uintptr(it^ * info.elem_size))
elem.id = info.elem.id
ok = true
+ index = it^
it^ += 1
}
}
@@ -69,10 +72,12 @@ iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
key.id = info.key.id
value.id = info.value.id
ok = true
+ it^ += 1
break
}
}
}
return
-} \ No newline at end of file
+}
+
diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin
index decba00ee..c04afb380 100644
--- a/core/reflect/reflect.odin
+++ b/core/reflect/reflect.odin
@@ -1015,6 +1015,74 @@ bit_set_is_big_endian :: proc(value: any, loc := #caller_location) -> bool {
}
+Bit_Field :: struct {
+ name: string,
+ type: ^Type_Info,
+ size: uintptr, // Size in bits
+ offset: uintptr, // Offset in bits
+ tag: Struct_Tag,
+}
+
+@(require_results)
+bit_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Bit_Field) {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return soa_zip(
+ name = s.names[:s.field_count],
+ type = s.types[:s.field_count],
+ size = s.bit_sizes[:s.field_count],
+ offset = s.bit_offsets[:s.field_count],
+ tag = ([^]Struct_Tag)(s.tags)[:s.field_count],
+ )
+ }
+ return nil
+}
+
+@(require_results)
+bit_field_names :: proc(T: typeid) -> []string {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return s.names[:s.field_count]
+ }
+ return nil
+}
+
+@(require_results)
+bit_field_types :: proc(T: typeid) -> []^Type_Info {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return s.types[:s.field_count]
+ }
+ return nil
+}
+
+@(require_results)
+bit_field_sizes :: proc(T: typeid) -> []uintptr {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return s.bit_sizes[:s.field_count]
+ }
+ return nil
+}
+
+@(require_results)
+bit_field_offsets :: proc(T: typeid) -> []uintptr {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return s.bit_offsets[:s.field_count]
+ }
+ return nil
+}
+
+@(require_results)
+bit_field_tags :: proc(T: typeid) -> []Struct_Tag {
+ ti := runtime.type_info_base(type_info_of(T))
+ if s, ok := ti.variant.(runtime.Type_Info_Bit_Field); ok {
+ return transmute([]Struct_Tag)s.tags[:s.field_count]
+ }
+ return nil
+}
+
@(require_results)
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
if a == nil { return }
@@ -1698,4 +1766,4 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
runtime.print_typeid(a.id)
runtime.print_string("\n")
return true
-}
+} \ No newline at end of file
diff --git a/core/simd/x86/abm.odin b/core/simd/x86/abm.odin
index 9018a835a..4b07086ce 100644
--- a/core/simd/x86/abm.odin
+++ b/core/simd/x86/abm.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/adx.odin b/core/simd/x86/adx.odin
index 5750ae627..9c6ae063a 100644
--- a/core/simd/x86/adx.odin
+++ b/core/simd/x86/adx.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(require_results)
diff --git a/core/simd/x86/aes.odin b/core/simd/x86/aes.odin
index a2cd2e4d3..338381422 100644
--- a/core/simd/x86/aes.odin
+++ b/core/simd/x86/aes.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(require_results, enable_target_feature = "aes")
diff --git a/core/simd/x86/cmpxchg16b.odin b/core/simd/x86/cmpxchg16b.odin
index 1307a9cf2..78ebd182f 100644
--- a/core/simd/x86/cmpxchg16b.odin
+++ b/core/simd/x86/cmpxchg16b.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/fxsr.odin b/core/simd/x86/fxsr.odin
index a9213fed2..ab8cdca7d 100644
--- a/core/simd/x86/fxsr.odin
+++ b/core/simd/x86/fxsr.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(enable_target_feature="fxsr")
diff --git a/core/simd/x86/pclmulqdq.odin b/core/simd/x86/pclmulqdq.odin
index e827bf6b9..14e633c06 100644
--- a/core/simd/x86/pclmulqdq.odin
+++ b/core/simd/x86/pclmulqdq.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(require_results, enable_target_feature="pclmul")
diff --git a/core/simd/x86/rdtsc.odin b/core/simd/x86/rdtsc.odin
index 8a8b13c4b..84c762274 100644
--- a/core/simd/x86/rdtsc.odin
+++ b/core/simd/x86/rdtsc.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(require_results)
diff --git a/core/simd/x86/sha.odin b/core/simd/x86/sha.odin
index bc58e8504..8caa3a268 100644
--- a/core/simd/x86/sha.odin
+++ b/core/simd/x86/sha.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
@(require_results, enable_target_feature="sha")
diff --git a/core/simd/x86/sse.odin b/core/simd/x86/sse.odin
index 4dac50234..1b4a863b6 100644
--- a/core/simd/x86/sse.odin
+++ b/core/simd/x86/sse.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/sse2.odin b/core/simd/x86/sse2.odin
index 2e3eb8523..aaddbe6b4 100644
--- a/core/simd/x86/sse2.odin
+++ b/core/simd/x86/sse2.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/sse3.odin b/core/simd/x86/sse3.odin
index a905a7726..0e074c946 100644
--- a/core/simd/x86/sse3.odin
+++ b/core/simd/x86/sse3.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/sse41.odin b/core/simd/x86/sse41.odin
index c2c1abc2d..81089ed63 100644
--- a/core/simd/x86/sse41.odin
+++ b/core/simd/x86/sse41.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "core:simd"
diff --git a/core/simd/x86/sse42.odin b/core/simd/x86/sse42.odin
index 7a674176b..1a5cb3f50 100644
--- a/core/simd/x86/sse42.odin
+++ b/core/simd/x86/sse42.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "core:simd"
diff --git a/core/simd/x86/ssse3.odin b/core/simd/x86/ssse3.odin
index 2026c7f53..07c846e7b 100644
--- a/core/simd/x86/ssse3.odin
+++ b/core/simd/x86/ssse3.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "base:intrinsics"
diff --git a/core/simd/x86/types.odin b/core/simd/x86/types.odin
index 06a2cd41e..ea0eff534 100644
--- a/core/simd/x86/types.odin
+++ b/core/simd/x86/types.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package simd_x86
import "core:simd"
diff --git a/core/slice/slice.odin b/core/slice/slice.odin
index 989fcc696..99ad15547 100644
--- a/core/slice/slice.odin
+++ b/core/slice/slice.odin
@@ -200,6 +200,17 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_
return false
}
when intrinsics.type_is_simple_compare(E) {
+ if len(a) == 0 {
+ // Empty slices are always equivalent to each other.
+ //
+ // This check is here in the event that a slice with a `data` of
+ // nil is compared against a slice with a non-nil `data` but a
+ // length of zero.
+ //
+ // In that case, `memory_compare` would return -1 or +1 because one
+ // of the pointers is nil.
+ return true
+ }
return runtime.memory_compare(raw_data(a), raw_data(b), len(a)*size_of(E)) == 0
} else {
for i in 0..<len(a) {
diff --git a/core/slice/sort_private.odin b/core/slice/sort_private.odin
index 487b51907..36637c4cd 100644
--- a/core/slice/sort_private.odin
+++ b/core/slice/sort_private.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package slice
import "base:intrinsics"
diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin
index dce9f834a..b1155c22f 100644
--- a/core/strconv/strconv.odin
+++ b/core/strconv/strconv.odin
@@ -7,11 +7,11 @@ Parses a boolean value from the input string
**Inputs**
- s: The input string
- - true: "1", "t", "T", "true", "TRUE", "True"
- - false: "0", "f", "F", "false", "FALSE", "False"
+ - true: "1", "t", "T", "true", "TRUE", "True"
+ - false: "0", "f", "F", "false", "FALSE", "False"
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
-**Returns**
+**Returns**
- result: The parsed boolean value (default: false)
- ok: A boolean indicating whether the parsing was successful
*/
@@ -29,7 +29,7 @@ parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool)
/*
Finds the integer value of the given rune
-**Inputs**
+**Inputs**
- r: The input rune to find the integer value of
**Returns** The integer value of the given rune
@@ -47,7 +47,7 @@ _digit_value :: proc(r: rune) -> int {
/*
Parses an integer value from the input string in the given base, without a prefix
-**Inputs**
+**Inputs**
- str: The input string to parse the integer value from
- base: The base of the integer value to be parsed (must be between 1 and 16)
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -65,7 +65,7 @@ Output:
-1234 false
-**Returns**
+**Returns**
- value: Parses an integer value from a string, in the given base, without a prefix.
- ok: ok=false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
*/
@@ -117,12 +117,12 @@ parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64,
/*
Parses an integer value from the input string in base 10, unless there's a prefix
-**Inputs**
+**Inputs**
- str: The input string to parse the integer value from
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
Example:
-
+
import "core:fmt"
import "core:strconv"
parse_i64_maybe_prefixed_example :: proc() {
@@ -132,13 +132,13 @@ Example:
n, ok = strconv.parse_i64_maybe_prefixed("0xeeee")
fmt.println(n,ok)
}
-
+
Output:
1234 true
61166 true
-**Returns**
+**Returns**
- value: The parsed integer value
- ok: ok=false if a valid integer could not be found, or if the input string contained more than just the number.
*/
@@ -200,14 +200,14 @@ parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base}
/*
Parses an unsigned 64-bit integer value from the input string without a prefix, using the specified base
-**Inputs**
+**Inputs**
- str: The input string to parse
- base: The base of the number system to use for parsing
- - Must be between 1 and 16 (inclusive)
+ - Must be between 1 and 16 (inclusive)
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
Example:
-
+
import "core:fmt"
import "core:strconv"
parse_u64_of_base_example :: proc() {
@@ -217,13 +217,13 @@ Example:
n, ok = strconv.parse_u64_of_base("5678eee",16)
fmt.println(n,ok)
}
-
+
Output:
1234 false
90672878 true
-**Returns**
+**Returns**
- value: The parsed uint64 value
- ok: A boolean indicating whether the parsing was successful
*/
@@ -261,15 +261,15 @@ parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64,
/*
Parses an unsigned 64-bit integer value from the input string, using the specified base or inferring the base from a prefix
-**Inputs**
+**Inputs**
- str: The input string to parse
- base: The base of the number system to use for parsing (default: 0)
- - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
- - If base is not 0, it will be used for parsing regardless of any prefix in the input string
+ - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
+ - If base is not 0, it will be used for parsing regardless of any prefix in the input string
- n: An optional pointer to an int to store the length of the parsed substring (default: nil)
Example:
-
+
import "core:fmt"
import "core:strconv"
parse_u64_maybe_prefixed_example :: proc() {
@@ -279,13 +279,13 @@ Example:
n, ok = strconv.parse_u64_maybe_prefixed("0xee")
fmt.println(n,ok)
}
-
+
Output:
1234 true
238 true
-**Returns**
+**Returns**
- value: The parsed uint64 value
- ok: ok=false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number.
*/
@@ -336,14 +336,14 @@ parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base}
/*
Parses a signed integer value from the input string, using the specified base or inferring the base from a prefix
-**Inputs**
+**Inputs**
- s: The input string to parse
- base: The base of the number system to use for parsing (default: 0)
- - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
- - If base is not 0, it will be used for parsing regardless of any prefix in the input string
+ - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
+ - If base is not 0, it will be used for parsing regardless of any prefix in the input string
Example:
-
+
import "core:fmt"
import "core:strconv"
parse_int_example :: proc() {
@@ -356,14 +356,14 @@ Example:
n, ok = strconv.parse_int("0xffff") // with prefix and inferred base
fmt.println(n,ok)
}
-
+
Output:
1234 true
65535 true
65535 true
-**Returns**
+**Returns**
- value: The parsed int value
- ok: `false` if no appropriate value could be found, or if the input string contained more than just the number.
*/
@@ -379,11 +379,11 @@ parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool)
/*
Parses an unsigned integer value from the input string, using the specified base or inferring the base from a prefix
-**Inputs**
+**Inputs**
- s: The input string to parse
- base: The base of the number system to use for parsing (default: 0, inferred)
- - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
- - If base is not 0, it will be used for parsing regardless of any prefix in the input string
+ - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
+ - If base is not 0, it will be used for parsing regardless of any prefix in the input string
Example:
@@ -1729,7 +1729,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
}
}
- if buf == nil {
+ if buf == nil || r < 0 {
return ""
}
diff --git a/core/strings/strings.odin b/core/strings/strings.odin
index 216d7ad79..dbc84f8b7 100644
--- a/core/strings/strings.odin
+++ b/core/strings/strings.odin
@@ -93,7 +93,7 @@ Inputs:
Returns:
- res: A string created from the null-terminated byte pointer and length
*/
-string_from_null_terminated_ptr :: proc(ptr: [^]byte, len: int) -> (res: string) {
+string_from_null_terminated_ptr :: proc "contextless" (ptr: [^]byte, len: int) -> (res: string) {
s := string(ptr[:len])
s = truncate_to_byte(s, 0)
return s
@@ -139,7 +139,7 @@ NOTE: Failure to find the byte results in returning the entire string.
Returns:
- res: The truncated string
*/
-truncate_to_byte :: proc(str: string, b: byte) -> (res: string) {
+truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) {
n := index_byte(str, b)
if n < 0 {
n = len(str)
@@ -261,7 +261,7 @@ Inputs:
Returns:
- result: `-1` if `lhs` comes first, `1` if `rhs` comes first, or `0` if they are equal
*/
-compare :: proc(lhs, rhs: string) -> (result: int) {
+compare :: proc "contextless" (lhs, rhs: string) -> (result: int) {
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
}
/*
@@ -710,20 +710,17 @@ The concatenated string, and an error if allocation fails
concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
return concatenate(a, allocator)
}
+
/*
Returns a substring of the input string `s` with the specified rune offset and length
-*Allocates Using Provided Allocator*
-
Inputs:
- s: The input string to cut
- rune_offset: The starting rune index (default is 0). In runes, not bytes.
- rune_length: The number of runes to include in the substring (default is 0, which returns the remainder of the string). In runes, not bytes.
-- allocator: (default is context.allocator)
Returns:
- res: The substring
-- err: An optional allocator error if one occured, `nil` otherwise
Example:
@@ -743,57 +740,71 @@ Output:
example
*/
-cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
+cut :: proc(s: string, rune_offset := int(0), rune_length := int(0)) -> (res: string) {
s := s; rune_length := rune_length
- context.allocator = allocator
- // If we signal that we want the entire remainder (length <= 0) *and*
- // the offset is zero, then we can early out by cloning the input
- if rune_offset == 0 && rune_length <= 0 {
- return clone(s)
+ count := 0
+ for _, offset in s {
+ if count == rune_offset {
+ s = s[offset:]
+ break
+ }
+ count += 1
}
- // We need to know if we have enough runes to cover offset + length.
- rune_count := utf8.rune_count_in_string(s)
-
- // We're asking for a substring starting after the end of the input string.
- // That's just an empty string.
- if rune_offset >= rune_count {
- return "", nil
+ if rune_length <= 1 {
+ return s
}
- // If we don't specify the length of the substring, use the remainder.
- if rune_length <= 0 {
- rune_length = rune_count - rune_offset
+ count = 0
+ for _, offset in s {
+ if count == rune_length {
+ s = s[:offset]
+ break
+ }
+ count += 1
}
+ return s
+}
- // We don't yet know how many bytes we need exactly.
- // But we do know it's bounded by the number of runes * 4 bytes,
- // and can be no more than the size of the input string.
- bytes_needed := min(rune_length * 4, len(s))
- buf := make([]u8, bytes_needed, allocator, loc) or_return
+/*
+Returns a substring of the input string `s` with the specified rune offset and length
- byte_offset := 0
- for i := 0; i < rune_count; i += 1 {
- _, w := utf8.decode_rune_in_string(s)
+*Allocates Using Provided Allocator*
- // If the rune is part of the substring, copy it to the output buffer.
- if i >= rune_offset {
- for j := 0; j < w; j += 1 {
- buf[byte_offset+j] = s[j]
- }
- byte_offset += w
- }
+Inputs:
+- s: The input string to cut
+- rune_offset: The starting rune index (default is 0). In runes, not bytes.
+- rune_length: The number of runes to include in the substring (default is 0, which returns the remainder of the string). In runes, not bytes.
+- allocator: (default is context.allocator)
- // We're done if we reach the end of the input string, *or*
- // if we've reached a specified length in runes.
- if rune_length > 0 {
- if i == rune_offset + rune_length - 1 { break }
- }
- s = s[w:]
+Returns:
+- res: The substring
+- err: An optional allocator error if one occured, `nil` otherwise
+
+Example:
+
+ import "core:fmt"
+ import "core:strings"
+
+ cut_example :: proc() {
+ fmt.println(strings.cut_clone("some example text", 0, 4)) // -> "some"
+ fmt.println(strings.cut_clone("some example text", 2, 2)) // -> "me"
+ fmt.println(strings.cut_clone("some example text", 5, 7)) // -> "example"
}
- return string(buf[:byte_offset]), nil
+
+Output:
+
+ some
+ me
+ example
+
+*/
+cut_clone :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
+ res = cut(s, rune_offset, rune_length)
+ return clone(res, allocator, loc)
}
+
/*
Splits the input string `s` into a slice of substrings separated by the specified `sep` string
@@ -1436,7 +1447,7 @@ Output:
-1
*/
-index_byte :: proc(s: string, c: byte) -> (res: int) {
+index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.index_byte(transmute([]u8)s, c)
}
/*
@@ -1471,7 +1482,7 @@ Output:
-1
*/
-last_index_byte :: proc(s: string, c: byte) -> (res: int) {
+last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.last_index_byte(transmute([]u8)s, c)
}
/*
@@ -1565,8 +1576,8 @@ Output:
-1
*/
-index :: proc(s, substr: string) -> (res: int) {
- hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
+index :: proc "contextless" (s, substr: string) -> (res: int) {
+ hash_str_rabin_karp :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := 0; i < len(s); i += 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i])
}
@@ -3316,3 +3327,106 @@ levenshtein_distance :: proc(a, b: string, allocator := context.allocator, loc :
return costs[n], nil
}
+
+@(private)
+internal_substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) {
+ sub = s
+ ok = true
+
+ rune_i: int
+
+ if rune_start > 0 {
+ ok = false
+ for _, i in sub {
+ if rune_start == rune_i {
+ ok = true
+ sub = sub[i:]
+ break
+ }
+ rune_i += 1
+ }
+ if !ok { return }
+ }
+
+ if rune_end >= rune_start {
+ ok = false
+ for _, i in sub {
+ if rune_end == rune_i {
+ ok = true
+ sub = sub[:i]
+ break
+ }
+ rune_i += 1
+ }
+
+ if rune_end == rune_i {
+ ok = true
+ }
+ }
+
+ return
+}
+
+/*
+Returns a substring of `s` that starts at rune index `rune_start` and goes up to `rune_end`.
+
+Think of it as slicing `s[rune_start:rune_end]` but rune-wise.
+
+Inputs:
+- s: the string to substring
+- rune_start: the start (inclusive) rune
+- rune_end: the end (exclusive) rune
+
+Returns:
+- sub: the substring
+- ok: whether the rune indexes where in bounds of the original string
+*/
+substring :: proc(s: string, rune_start: int, rune_end: int) -> (sub: string, ok: bool) {
+ if rune_start < 0 || rune_end < 0 || rune_end < rune_start {
+ return
+ }
+
+ return internal_substring(s, rune_start, rune_end)
+}
+
+/*
+Returns a substring of `s` that starts at rune index `rune_start` and goes up to the end of the string.
+
+Think of it as slicing `s[rune_start:]` but rune-wise.
+
+Inputs:
+- s: the string to substring
+- rune_start: the start (inclusive) rune
+
+Returns:
+- sub: the substring
+- ok: whether the rune indexes where in bounds of the original string
+*/
+substring_from :: proc(s: string, rune_start: int) -> (sub: string, ok: bool) {
+ if rune_start < 0 {
+ return
+ }
+
+ return internal_substring(s, rune_start, -1)
+}
+
+/*
+Returns a substring of `s` that goes up to rune index `rune_end`.
+
+Think of it as slicing `s[:rune_end]` but rune-wise.
+
+Inputs:
+- s: the string to substring
+- rune_end: the end (exclusive) rune
+
+Returns:
+- sub: the substring
+- ok: whether the rune indexes where in bounds of the original string
+*/
+substring_to :: proc(s: string, rune_end: int) -> (sub: string, ok: bool) {
+ if rune_end < 0 {
+ return
+ }
+
+ return internal_substring(s, -1, rune_end)
+}
diff --git a/core/sync/chan/chan.odin b/core/sync/chan/chan.odin
index 0c98124de..c470d15f3 100644
--- a/core/sync/chan/chan.odin
+++ b/core/sync/chan/chan.odin
@@ -22,19 +22,17 @@ Raw_Chan :: struct {
allocator: runtime.Allocator,
allocation_size: int,
msg_size: u16,
- closed: b16, // atomic
+ closed: b16, // guarded by `mutex`
mutex: sync.Mutex,
r_cond: sync.Cond,
w_cond: sync.Cond,
- r_waiting: int, // atomic
- w_waiting: int, // atomic
+ r_waiting: int, // guarded by `mutex`
+ w_waiting: int, // guarded by `mutex`
// Buffered
queue: ^Raw_Queue,
// Unbuffered
- r_mutex: sync.Mutex,
- w_mutex: sync.Mutex,
unbuffered_data: rawptr,
}
@@ -164,27 +162,30 @@ send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) {
}
if c.queue != nil { // buffered
sync.guard(&c.mutex)
- for c.queue.len == c.queue.cap {
- sync.atomic_add(&c.w_waiting, 1)
+ for !c.closed && c.queue.len == c.queue.cap {
+ c.w_waiting += 1
sync.wait(&c.w_cond, &c.mutex)
- sync.atomic_sub(&c.w_waiting, 1)
+ c.w_waiting -= 1
+ }
+
+ if c.closed {
+ return false
}
ok = raw_queue_push(c.queue, msg_in)
- if sync.atomic_load(&c.r_waiting) > 0 {
+ if c.r_waiting > 0 {
sync.signal(&c.r_cond)
}
} else if c.unbuffered_data != nil { // unbuffered
- sync.guard(&c.w_mutex)
sync.guard(&c.mutex)
- if sync.atomic_load(&c.closed) {
+ if c.closed {
return false
}
mem.copy(c.unbuffered_data, msg_in, int(c.msg_size))
- sync.atomic_add(&c.w_waiting, 1)
- if sync.atomic_load(&c.r_waiting) > 0 {
+ c.w_waiting += 1
+ if c.r_waiting > 0 {
sync.signal(&c.r_cond)
}
sync.wait(&c.w_cond, &c.mutex)
@@ -201,13 +202,13 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) {
if c.queue != nil { // buffered
sync.guard(&c.mutex)
for c.queue.len == 0 {
- if sync.atomic_load(&c.closed) {
+ if c.closed {
return
}
- sync.atomic_add(&c.r_waiting, 1)
+ c.r_waiting += 1
sync.wait(&c.r_cond, &c.mutex)
- sync.atomic_sub(&c.r_waiting, 1)
+ c.r_waiting -= 1
}
msg := raw_queue_pop(c.queue)
@@ -215,27 +216,26 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) {
mem.copy(msg_out, msg, int(c.msg_size))
}
- if sync.atomic_load(&c.w_waiting) > 0 {
+ if c.w_waiting > 0 {
sync.signal(&c.w_cond)
}
ok = true
} else if c.unbuffered_data != nil { // unbuffered
- sync.guard(&c.r_mutex)
sync.guard(&c.mutex)
- for !sync.atomic_load(&c.closed) &&
- sync.atomic_load(&c.w_waiting) == 0 {
- sync.atomic_add(&c.r_waiting, 1)
+ for !c.closed &&
+ c.w_waiting == 0 {
+ c.r_waiting += 1
sync.wait(&c.r_cond, &c.mutex)
- sync.atomic_sub(&c.r_waiting, 1)
+ c.r_waiting -= 1
}
- if sync.atomic_load(&c.closed) {
+ if c.closed {
return
}
mem.copy(msg_out, c.unbuffered_data, int(c.msg_size))
- sync.atomic_sub(&c.w_waiting, 1)
+ c.w_waiting -= 1
sync.signal(&c.w_cond)
ok = true
@@ -255,21 +255,24 @@ try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool)
return false
}
+ if c.closed {
+ return false
+ }
+
ok = raw_queue_push(c.queue, msg_in)
- if sync.atomic_load(&c.r_waiting) > 0 {
+ if c.r_waiting > 0 {
sync.signal(&c.r_cond)
}
} else if c.unbuffered_data != nil { // unbuffered
- sync.guard(&c.w_mutex)
sync.guard(&c.mutex)
- if sync.atomic_load(&c.closed) {
+ if c.closed {
return false
}
mem.copy(c.unbuffered_data, msg_in, int(c.msg_size))
- sync.atomic_add(&c.w_waiting, 1)
- if sync.atomic_load(&c.r_waiting) > 0 {
+ c.w_waiting += 1
+ if c.r_waiting > 0 {
sync.signal(&c.r_cond)
}
sync.wait(&c.w_cond, &c.mutex)
@@ -294,21 +297,19 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool {
mem.copy(msg_out, msg, int(c.msg_size))
}
- if sync.atomic_load(&c.w_waiting) > 0 {
+ if c.w_waiting > 0 {
sync.signal(&c.w_cond)
}
return true
} else if c.unbuffered_data != nil { // unbuffered
- sync.guard(&c.r_mutex)
sync.guard(&c.mutex)
- if sync.atomic_load(&c.closed) ||
- sync.atomic_load(&c.w_waiting) == 0 {
+ if c.closed || c.w_waiting == 0 {
return false
}
mem.copy(msg_out, c.unbuffered_data, int(c.msg_size))
- sync.atomic_sub(&c.w_waiting, 1)
+ c.w_waiting -= 1
sync.signal(&c.w_cond)
return true
@@ -351,10 +352,10 @@ close :: proc "contextless" (c: ^Raw_Chan) -> bool {
return false
}
sync.guard(&c.mutex)
- if sync.atomic_load(&c.closed) {
+ if c.closed {
return false
}
- sync.atomic_store(&c.closed, true)
+ c.closed = true
sync.broadcast(&c.r_cond)
sync.broadcast(&c.w_cond)
return true
@@ -366,7 +367,7 @@ is_closed :: proc "contextless" (c: ^Raw_Chan) -> bool {
return true
}
sync.guard(&c.mutex)
- return bool(sync.atomic_load(&c.closed))
+ return bool(c.closed)
}
@@ -421,22 +422,21 @@ raw_queue_pop :: proc "contextless" (q: ^Raw_Queue) -> (data: rawptr) {
@(require_results)
can_recv :: proc "contextless" (c: ^Raw_Chan) -> bool {
+ sync.guard(&c.mutex)
if is_buffered(c) {
- return len(c) > 0
+ return c.queue.len > 0
}
- sync.guard(&c.mutex)
- return sync.atomic_load(&c.w_waiting) > 0
+ return c.w_waiting > 0
}
@(require_results)
can_send :: proc "contextless" (c: ^Raw_Chan) -> bool {
+ sync.guard(&c.mutex)
if is_buffered(c) {
- sync.guard(&c.mutex)
- return len(c) < cap(c)
+ return c.queue.len < c.queue.cap
}
- sync.guard(&c.mutex)
- return sync.atomic_load(&c.r_waiting) > 0
+ return c.w_waiting == 0
}
@@ -485,4 +485,4 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []
ok = send_raw(sends[sel.idx], send_msgs[sel.idx])
}
return
-} \ No newline at end of file
+}
diff --git a/core/sync/doc.odin b/core/sync/doc.odin
index 9876c46fb..320732ea7 100644
--- a/core/sync/doc.odin
+++ b/core/sync/doc.odin
@@ -7,8 +7,8 @@ synchronize threads' access to shared memory.
To limit or control the threads' access to shared memory typically the
following approaches are used:
-* Locks
-* Lock-free
+- Locks
+- Lock-free
When using locks, sections of the code that access shared memory (also known as
**critical sections**) are guarded by locks, allowing limited access to threads
@@ -18,4 +18,4 @@ In lock-free programming the data itself is organized in such a way that threads
don't intervene much. It can be done via segmenting the data between threads,
and/or by using atomic operations.
*/
-package sync \ No newline at end of file
+package sync
diff --git a/core/sync/extended.odin b/core/sync/extended.odin
index b446fefa0..30b1b2770 100644
--- a/core/sync/extended.odin
+++ b/core/sync/extended.odin
@@ -8,7 +8,7 @@ _ :: vg
Wait group.
Wait group is a synchronization primitive used by the waiting thread to wait,
-until a all working threads finish work.
+until all working threads finish work.
The waiting thread first sets the number of working threads it will expect to
wait for using `wait_group_add` call, and start waiting using `wait_group_wait`
@@ -35,7 +35,7 @@ Wait_Group :: struct #no_copy {
/*
Increment an internal counter of a wait group.
-This procedure atomicaly increments a number to the specified wait group's
+This procedure atomically increments a number to the specified wait group's
internal counter by a specified amount. This operation can be done on any
thread.
*/
@@ -48,12 +48,12 @@ wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
atomic_add(&wg.counter, delta)
if wg.counter < 0 {
- _panic("sync.Wait_Group negative counter")
+ panic_contextless("sync.Wait_Group negative counter")
}
if wg.counter == 0 {
cond_broadcast(&wg.cond)
if wg.counter != 0 {
- _panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
+ panic_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
}
@@ -81,7 +81,7 @@ wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
if wg.counter != 0 {
cond_wait(&wg.cond, &wg.mutex)
if wg.counter != 0 {
- _panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
+ panic_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
}
@@ -105,7 +105,7 @@ wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: t
return false
}
if wg.counter != 0 {
- _panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
+ panic_contextless("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
return true
@@ -121,7 +121,7 @@ When `barrier_wait` procedure is called by any thread, that thread will block
the execution, until all threads associated with the barrier reach the same
point of execution and also call `barrier_wait`.
-when barrier is initialized, a `thread_count` parameter is passed, signifying
+When a barrier is initialized, a `thread_count` parameter is passed, signifying
the amount of participant threads of the barrier. The barrier also keeps track
of an internal atomic counter. When a thread calls `barrier_wait`, the internal
counter is incremented. When the internal counter reaches `thread_count`, it is
@@ -208,7 +208,7 @@ Represents a thread synchronization primitive that, when signalled, releases one
single waiting thread and then resets automatically to a state where it can be
signalled again.
-When a thread calls `auto_reset_event_wait`, it's execution will be blocked,
+When a thread calls `auto_reset_event_wait`, its execution will be blocked,
until the event is signalled by another thread. The call to
`auto_reset_event_signal` wakes up exactly one thread waiting for the event.
*/
@@ -228,15 +228,15 @@ thread.
*/
auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
old_status := atomic_load_explicit(&e.status, .Relaxed)
+ new_status := old_status + 1 if old_status < 1 else 1
for {
- new_status := old_status + 1 if old_status < 1 else 1
if _, ok := atomic_compare_exchange_weak_explicit(&e.status, old_status, new_status, .Release, .Relaxed); ok {
break
}
-
- if old_status < 0 {
- sema_post(&e.sema)
- }
+ cpu_relax()
+ }
+ if old_status < 0 {
+ sema_post(&e.sema)
}
}
@@ -297,7 +297,7 @@ waiting to acquire the lock, exactly one of those threads is unblocked and
allowed into the critical section.
*/
ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
- atomic_add_explicit(&m.serving, 1, .Relaxed)
+ atomic_add_explicit(&m.serving, 1, .Release)
}
/*
@@ -331,8 +331,8 @@ Benaphore.
A benaphore is a combination of an atomic variable and a semaphore that can
improve locking efficiency in a no-contention system. Acquiring a benaphore
-lock doesn't call into an internal semaphore, if no other thread in a middle of
-a critical section.
+lock doesn't call into an internal semaphore, if no other thread is in the
+middle of a critical section.
Once a lock on a benaphore is acquired by a thread, no other thread is allowed
into any critical sections, associted with the same benaphore, until the lock
@@ -355,7 +355,7 @@ from entering any critical sections associated with the same benaphore, until
until the lock is released.
*/
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
- if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
+ if atomic_add_explicit(&b.counter, 1, .Acquire) > 0 {
sema_wait(&b.sema)
}
}
@@ -381,10 +381,10 @@ Release a lock on a benaphore.
This procedure releases a lock on the specified benaphore. If any of the threads
are waiting on the lock, exactly one thread is allowed into a critical section
-associated with the same banaphore.
+associated with the same benaphore.
*/
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
- if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
+ if atomic_sub_explicit(&b.counter, 1, .Release) > 1 {
sema_post(&b.sema)
}
}
@@ -418,8 +418,8 @@ benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
/*
Recursive benaphore.
-Recurisve benaphore is just like a plain benaphore, except it allows reentrancy
-into the critical section.
+A recursive benaphore is just like a plain benaphore, except it allows
+reentrancy into the critical section.
When a lock is acquired on a benaphore, all other threads attempting to
acquire a lock on the same benaphore will be blocked from any critical sections,
@@ -449,13 +449,15 @@ recursive benaphore, until the lock is released.
*/
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id()
- if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
- if tid != b.owner {
- sema_wait(&b.sema)
+ check_owner: if tid != atomic_load_explicit(&b.owner, .Acquire) {
+ atomic_add_explicit(&b.counter, 1, .Relaxed)
+ if _, ok := atomic_compare_exchange_strong_explicit(&b.owner, 0, tid, .Release, .Relaxed); ok {
+ break check_owner
}
+ sema_wait(&b.sema)
+ atomic_store_explicit(&b.owner, tid, .Release)
}
// inside the lock
- b.owner = tid
b.recursion += 1
}
@@ -472,15 +474,14 @@ benaphore, until the lock is released.
*/
recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
tid := current_thread_id()
- if b.owner == tid {
- atomic_add_explicit(&b.counter, 1, .Acquire)
- }
-
- if v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire); v != 0 {
+ check_owner: if tid != atomic_load_explicit(&b.owner, .Acquire) {
+ if _, ok := atomic_compare_exchange_strong_explicit(&b.owner, 0, tid, .Release, .Relaxed); ok {
+ atomic_add_explicit(&b.counter, 1, .Relaxed)
+ break check_owner
+ }
return false
}
// inside the lock
- b.owner = tid
b.recursion += 1
return true
}
@@ -494,14 +495,14 @@ for other threads for entering.
*/
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id()
- _assert(tid == b.owner, "tid != b.owner")
+ assert_contextless(tid == atomic_load_explicit(&b.owner, .Relaxed), "tid != b.owner")
b.recursion -= 1
recursion := b.recursion
+
if recursion == 0 {
- b.owner = 0
- }
- if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
- if recursion == 0 {
+ if atomic_sub_explicit(&b.counter, 1, .Relaxed) == 1 {
+ atomic_store_explicit(&b.owner, 0, .Release)
+ } else {
sema_post(&b.sema)
}
}
@@ -740,4 +741,4 @@ Make event available.
one_shot_event_signal :: proc "contextless" (e: ^One_Shot_Event) {
atomic_store_explicit(&e.state, 1, .Release)
futex_broadcast(&e.state)
-} \ No newline at end of file
+}
diff --git a/core/sync/futex_darwin.odin b/core/sync/futex_darwin.odin
index fca9aadfe..10ff7bfbb 100644
--- a/core/sync/futex_darwin.odin
+++ b/core/sync/futex_darwin.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin
+#+private
+#+build darwin
package sync
import "core:c"
@@ -12,6 +12,8 @@ foreign System {
// __ulock_wait is not available on 10.15
// See https://github.com/odin-lang/Odin/issues/1959
__ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
+ // >= MacOS 11.
+ __ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
__ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
}
@@ -48,22 +50,29 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
case -ETIMEDOUT:
return false
case:
- _panic("darwin.os_sync_wait_on_address_with_timeout failure")
+ panic_contextless("darwin.os_sync_wait_on_address_with_timeout failure")
}
} else {
- timeout_ns := u32(duration)
- s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
+ when darwin.ULOCK_WAIT_2_AVAILABLE {
+ timeout_ns := u64(duration)
+ s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
+ } else {
+ timeout_us := u32(duration / time.Microsecond)
+ s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_us)
+ }
+
if s >= 0 {
return true
}
+
switch s {
case EINTR, EFAULT:
return true
case ETIMEDOUT:
return false
case:
- _panic("futex_wait failure")
+ panic_contextless("futex_wait failure")
}
return true
@@ -83,7 +92,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
case -ENOENT:
return
case:
- _panic("darwin.os_sync_wake_by_address_any failure")
+ panic_contextless("darwin.os_sync_wake_by_address_any failure")
}
}
} else {
@@ -99,7 +108,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
case ENOENT:
return
case:
- _panic("futex_wake_single failure")
+ panic_contextless("futex_wake_single failure")
}
}
@@ -119,7 +128,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
case -ENOENT:
return
case:
- _panic("darwin.os_sync_wake_by_address_all failure")
+ panic_contextless("darwin.os_sync_wake_by_address_all failure")
}
}
} else {
@@ -135,7 +144,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
case ENOENT:
return
case:
- _panic("futex_wake_all failure")
+ panic_contextless("futex_wake_all failure")
}
}
diff --git a/core/sync/futex_freebsd.odin b/core/sync/futex_freebsd.odin
index ac6e2400a..e3f95b146 100644
--- a/core/sync/futex_freebsd.odin
+++ b/core/sync/futex_freebsd.odin
@@ -1,5 +1,5 @@
-//+private
-//+build freebsd
+#+private
+#+build freebsd
package sync
import "core:c"
@@ -21,7 +21,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
continue
}
- _panic("_futex_wait failure")
+ panic_contextless("_futex_wait failure")
}
unreachable()
@@ -44,14 +44,14 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
return false
}
- _panic("_futex_wait_with_timeout failure")
+ panic_contextless("_futex_wait_with_timeout failure")
}
_futex_signal :: proc "contextless" (f: ^Futex) {
errno := freebsd._umtx_op(f, .WAKE, 1, nil, nil)
if errno != nil {
- _panic("_futex_signal failure")
+ panic_contextless("_futex_signal failure")
}
}
@@ -59,6 +59,6 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
errno := freebsd._umtx_op(f, .WAKE, cast(c.ulong)max(i32), nil, nil)
if errno != nil {
- _panic("_futex_broadcast failure")
+ panic_contextless("_futex_broadcast failure")
}
}
diff --git a/core/sync/futex_haiku.odin b/core/sync/futex_haiku.odin
index 6fe5894a0..21d07b801 100644
--- a/core/sync/futex_haiku.odin
+++ b/core/sync/futex_haiku.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package sync
import "core:c"
diff --git a/core/sync/futex_linux.odin b/core/sync/futex_linux.odin
index fe57c12ed..52143880b 100644
--- a/core/sync/futex_linux.odin
+++ b/core/sync/futex_linux.odin
@@ -1,5 +1,5 @@
-//+private
-//+build linux
+#+private
+#+build linux
package sync
import "core:time"
@@ -15,7 +15,7 @@ _futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool {
return true
case:
// TODO(flysand): More descriptive panic messages based on the vlaue of `errno`
- _panic("futex_wait failure")
+ panic_contextless("futex_wait failure")
}
}
@@ -34,7 +34,7 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
case .NONE, .EINTR, .EAGAIN:
return true
case:
- _panic("futex_wait_with_timeout failure")
+ panic_contextless("futex_wait_with_timeout failure")
}
}
@@ -44,7 +44,7 @@ _futex_signal :: proc "contextless" (futex: ^Futex) {
case .NONE:
return
case:
- _panic("futex_wake_single failure")
+ panic_contextless("futex_wake_single failure")
}
}
@@ -57,6 +57,6 @@ _futex_broadcast :: proc "contextless" (futex: ^Futex) {
case .NONE:
return
case:
- _panic("_futex_wake_all failure")
+ panic_contextless("_futex_wake_all failure")
}
}
diff --git a/core/sync/futex_netbsd.odin b/core/sync/futex_netbsd.odin
index d12409f32..e49b25b02 100644
--- a/core/sync/futex_netbsd.odin
+++ b/core/sync/futex_netbsd.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package sync
import "base:intrinsics"
@@ -35,7 +35,7 @@ _futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool {
case EINTR, EAGAIN:
return true
case:
- _panic("futex_wait failure")
+ panic_contextless("futex_wait failure")
}
}
return true
@@ -55,7 +55,7 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
case ETIMEDOUT:
return false
case:
- _panic("futex_wait_with_timeout failure")
+ panic_contextless("futex_wait_with_timeout failure")
}
}
return true
@@ -63,12 +63,12 @@ _futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, du
_futex_signal :: proc "contextless" (futex: ^Futex) {
if _, ok := intrinsics.syscall_bsd(unix.SYS___futex, uintptr(futex), FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); !ok {
- _panic("futex_wake_single failure")
+ panic_contextless("futex_wake_single failure")
}
}
_futex_broadcast :: proc "contextless" (futex: ^Futex) {
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")
+ panic_contextless("_futex_wake_all failure")
}
}
diff --git a/core/sync/futex_openbsd.odin b/core/sync/futex_openbsd.odin
index 4883a0841..7d3cc8578 100644
--- a/core/sync/futex_openbsd.odin
+++ b/core/sync/futex_openbsd.odin
@@ -1,5 +1,5 @@
-//+private
-//+build openbsd
+#+private
+#+build openbsd
package sync
import "core:c"
@@ -36,7 +36,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
return false
}
- _panic("futex_wait failure")
+ panic_contextless("futex_wait failure")
}
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
@@ -62,14 +62,14 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
return false
}
- _panic("futex_wait_with_timeout failure")
+ panic_contextless("futex_wait_with_timeout failure")
}
_futex_signal :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
if res == -1 {
- _panic("futex_wake_single failure")
+ panic_contextless("futex_wake_single failure")
}
}
@@ -77,6 +77,6 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
if res == -1 {
- _panic("_futex_wake_all failure")
+ panic_contextless("_futex_wake_all failure")
}
}
diff --git a/core/sync/futex_wasm.odin b/core/sync/futex_wasm.odin
index de88e8198..0f9659a02 100644
--- a/core/sync/futex_wasm.odin
+++ b/core/sync/futex_wasm.odin
@@ -1,5 +1,5 @@
-//+private
-//+build wasm32, wasm64p32
+#+private
+#+build wasm32, wasm64p32
package sync
import "base:intrinsics"
@@ -10,7 +10,7 @@ import "core:time"
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
when !intrinsics.has_target_feature("atomics") {
- _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
+ panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
} else {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
return s != 0
@@ -19,7 +19,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
when !intrinsics.has_target_feature("atomics") {
- _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
+ panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
} else {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
return s != 0
@@ -28,7 +28,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, durati
_futex_signal :: proc "contextless" (f: ^Futex) {
when !intrinsics.has_target_feature("atomics") {
- _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
+ panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
} else {
loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
@@ -41,7 +41,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
when !intrinsics.has_target_feature("atomics") {
- _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
+ panic_contextless("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it")
} else {
loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
diff --git a/core/sync/futex_windows.odin b/core/sync/futex_windows.odin
index 6a26baf5b..bb9686a1a 100644
--- a/core/sync/futex_windows.odin
+++ b/core/sync/futex_windows.odin
@@ -1,5 +1,5 @@
-//+private
-//+build windows
+#+private
+#+build windows
package sync
import "core:time"
diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin
index a22824481..f091de045 100644
--- a/core/sync/primitives.odin
+++ b/core/sync/primitives.odin
@@ -1,6 +1,5 @@
package sync
-import "base:runtime"
import "core:time"
/*
@@ -390,7 +389,7 @@ recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
A condition variable.
`Cond` implements a condition variable, a rendezvous point for threads waiting
-for signalling the occurence of an event. Condition variables are used on
+for signalling the occurence of an event. Condition variables are used in
conjuction with mutexes to provide a shared access to one or more shared
variable.
@@ -560,7 +559,7 @@ futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
return
}
ok := _futex_wait(f, expected)
- _assert(ok, "futex_wait failure")
+ assert_contextless(ok, "futex_wait failure")
}
/*
@@ -597,18 +596,3 @@ Wake up multiple threads waiting on a futex.
futex_broadcast :: proc "contextless" (f: ^Futex) {
_futex_broadcast(f)
}
-
-
-@(private)
-_assert :: proc "contextless" (cond: bool, msg: string) {
- if !cond {
- _panic(msg)
- }
-}
-
-@(private)
-_panic :: proc "contextless" (msg: string) -> ! {
- runtime.print_string(msg)
- runtime.print_byte('\n')
- runtime.trap()
-}
diff --git a/core/sync/primitives_atomic.odin b/core/sync/primitives_atomic.odin
index 2cf25ac11..3c4324eb7 100644
--- a/core/sync/primitives_atomic.odin
+++ b/core/sync/primitives_atomic.odin
@@ -240,7 +240,7 @@ atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
tid := current_thread_id()
- _assert(tid == m.owner, "tid != m.owner")
+ assert_contextless(tid == m.owner, "tid != m.owner")
m.recursion -= 1
recursion := m.recursion
if recursion == 0 {
@@ -338,7 +338,7 @@ atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {
original_count := atomic_load_explicit(&s.count, .Relaxed)
for original_count == 0 {
futex_wait(&s.count, u32(original_count))
- original_count = s.count
+ original_count = atomic_load_explicit(&s.count, .Relaxed)
}
if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) {
return
@@ -361,7 +361,7 @@ atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration:
if !futex_wait_with_timeout(&s.count, u32(original_count), remaining) {
return false
}
- original_count = s.count
+ original_count = atomic_load_explicit(&s.count, .Relaxed)
}
if original_count == atomic_compare_exchange_strong_explicit(&s.count, original_count, original_count-1, .Acquire, .Acquire) {
return true
diff --git a/core/sync/primitives_darwin.odin b/core/sync/primitives_darwin.odin
index 146f69e86..141cea744 100644
--- a/core/sync/primitives_darwin.odin
+++ b/core/sync/primitives_darwin.odin
@@ -1,5 +1,5 @@
-//+build darwin
-//+private
+#+build darwin
+#+private
package sync
import "core:c"
diff --git a/core/sync/primitives_freebsd.odin b/core/sync/primitives_freebsd.odin
index 2d7cbf18d..fe6b11e72 100644
--- a/core/sync/primitives_freebsd.odin
+++ b/core/sync/primitives_freebsd.odin
@@ -1,5 +1,5 @@
-//+build freebsd
-//+private
+#+build freebsd
+#+private
package sync
import "core:c"
diff --git a/core/sync/primitives_haiku.odin b/core/sync/primitives_haiku.odin
index 4b8f6b02d..69d005206 100644
--- a/core/sync/primitives_haiku.odin
+++ b/core/sync/primitives_haiku.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package sync
import "core:sys/haiku"
diff --git a/core/sync/primitives_internal.odin b/core/sync/primitives_internal.odin
index 23483aef5..4478a77d2 100644
--- a/core/sync/primitives_internal.odin
+++ b/core/sync/primitives_internal.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package sync
import "core:time"
diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin
index aa7a8b4b2..bf04f8d99 100644
--- a/core/sync/primitives_linux.odin
+++ b/core/sync/primitives_linux.odin
@@ -1,5 +1,5 @@
-//+build linux
-//+private
+#+build linux
+#+private
package sync
import "core:sys/linux"
diff --git a/core/sync/primitives_netbsd.odin b/core/sync/primitives_netbsd.odin
index 594f2ff5c..66da0745a 100644
--- a/core/sync/primitives_netbsd.odin
+++ b/core/sync/primitives_netbsd.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package sync
foreign import libc "system:c"
diff --git a/core/sync/primitives_openbsd.odin b/core/sync/primitives_openbsd.odin
index ff3ff837f..1f6efd8f7 100644
--- a/core/sync/primitives_openbsd.odin
+++ b/core/sync/primitives_openbsd.odin
@@ -1,5 +1,5 @@
-//+build openbsd
-//+private
+#+build openbsd
+#+private
package sync
foreign import libc "system:c"
diff --git a/core/sync/primitives_wasm.odin b/core/sync/primitives_wasm.odin
index f8d9ab657..8906d96be 100644
--- a/core/sync/primitives_wasm.odin
+++ b/core/sync/primitives_wasm.odin
@@ -1,5 +1,5 @@
-//+private
-//+build wasm32, wasm64p32
+#+private
+#+build wasm32, wasm64p32
package sync
_current_thread_id :: proc "contextless" () -> int {
diff --git a/core/sync/primitives_windows.odin b/core/sync/primitives_windows.odin
index 9f5bfc280..744bc248b 100644
--- a/core/sync/primitives_windows.odin
+++ b/core/sync/primitives_windows.odin
@@ -1,5 +1,5 @@
-//+build windows
-//+private
+#+build windows
+#+private
package sync
import "core:time"
diff --git a/core/sys/darwin/CoreFoundation/CFString.odin b/core/sys/darwin/CoreFoundation/CFString.odin
index 6ad3c5bfc..24485a494 100644
--- a/core/sys/darwin/CoreFoundation/CFString.odin
+++ b/core/sys/darwin/CoreFoundation/CFString.odin
@@ -1,7 +1,5 @@
package CoreFoundation
-import "base:runtime"
-
foreign import CoreFoundation "system:CoreFoundation.framework"
String :: distinct TypeRef // same as CFStringRef
@@ -9,157 +7,157 @@ String :: distinct TypeRef // same as CFStringRef
StringEncoding :: distinct u32
StringBuiltInEncodings :: enum StringEncoding {
- MacRoman = 0,
+ MacRoman = 0,
WindowsLatin1 = 0x0500,
- ISOLatin1 = 0x0201,
+ ISOLatin1 = 0x0201,
NextStepLatin = 0x0B01,
- ASCII = 0x0600,
- Unicode = 0x0100,
- UTF8 = 0x08000100,
+ ASCII = 0x0600,
+ Unicode = 0x0100,
+ UTF8 = 0x08000100,
NonLossyASCII = 0x0BFF,
- UTF16 = 0x0100,
+ UTF16 = 0x0100,
UTF16BE = 0x10000100,
UTF16LE = 0x14000100,
- UTF32 = 0x0c000100,
- UTF32BE = 0x18000100,
- UTF32LE = 0x1c000100,
+ UTF32 = 0x0c000100,
+ UTF32BE = 0x18000100,
+ UTF32LE = 0x1c000100,
}
StringEncodings :: enum Index {
- MacJapanese = 1,
- MacChineseTrad = 2,
- MacKorean = 3,
- MacArabic = 4,
- MacHebrew = 5,
- MacGreek = 6,
- MacCyrillic = 7,
- MacDevanagari = 9,
- MacGurmukhi = 10,
- MacGujarati = 11,
- MacOriya = 12,
- MacBengali = 13,
- MacTamil = 14,
- MacTelugu = 15,
- MacKannada = 16,
- MacMalayalam = 17,
- MacSinhalese = 18,
- MacBurmese = 19,
- MacKhmer = 20,
- MacThai = 21,
- MacLaotian = 22,
- MacGeorgian = 23,
- MacArmenian = 24,
- MacChineseSimp = 25,
- MacTibetan = 26,
- MacMongolian = 27,
- MacEthiopic = 28,
- MacCentralEurRoman = 29,
- MacVietnamese = 30,
- MacExtArabic = 31,
- MacSymbol = 33,
- MacDingbats = 34,
- MacTurkish = 35,
- MacCroatian = 36,
- MacIcelandic = 37,
- MacRomanian = 38,
- MacCeltic = 39,
- MacGaelic = 40,
- MacFarsi = 0x8C,
- MacUkrainian = 0x98,
- MacInuit = 0xEC,
- MacVT100 = 0xFC,
- MacHFS = 0xFF,
- ISOLatin2 = 0x0202,
- ISOLatin3 = 0x0203,
- ISOLatin4 = 0x0204,
- ISOLatinCyrillic = 0x0205,
- ISOLatinArabic = 0x0206,
- ISOLatinGreek = 0x0207,
- ISOLatinHebrew = 0x0208,
- ISOLatin5 = 0x0209,
- ISOLatin6 = 0x020A,
- ISOLatinThai = 0x020B,
- ISOLatin7 = 0x020D,
- ISOLatin8 = 0x020E,
- ISOLatin9 = 0x020F,
- ISOLatin10 = 0x0210,
- DOSLatinUS = 0x0400,
- DOSGreek = 0x0405,
- DOSBalticRim = 0x0406,
- DOSLatin1 = 0x0410,
- DOSGreek1 = 0x0411,
- DOSLatin2 = 0x0412,
- DOSCyrillic = 0x0413,
- DOSTurkish = 0x0414,
- DOSPortuguese = 0x0415,
- DOSIcelandic = 0x0416,
- DOSHebrew = 0x0417,
- DOSCanadianFrench = 0x0418,
- DOSArabic = 0x0419,
- DOSNordic = 0x041A,
- DOSRussian = 0x041B,
- DOSGreek2 = 0x041C,
- DOSThai = 0x041D,
- DOSJapanese = 0x0420,
- DOSChineseSimplif = 0x0421,
- DOSKorean = 0x0422,
- DOSChineseTrad = 0x0423,
- WindowsLatin2 = 0x0501,
- WindowsCyrillic = 0x0502,
- WindowsGreek = 0x0503,
- WindowsLatin5 = 0x0504,
- WindowsHebrew = 0x0505,
- WindowsArabic = 0x0506,
- WindowsBalticRim = 0x0507,
- WindowsVietnamese = 0x0508,
- WindowsKoreanJohab = 0x0510,
- ANSEL = 0x0601,
- JIS_X0201_76 = 0x0620,
- JIS_X0208_83 = 0x0621,
- JIS_X0208_90 = 0x0622,
- JIS_X0212_90 = 0x0623,
- JIS_C6226_78 = 0x0624,
- ShiftJIS_X0213 = 0x0628,
- ShiftJIS_X0213_MenKuTen = 0x0629,
- GB_2312_80 = 0x0630,
- GBK_95 = 0x0631,
- GB_18030_2000 = 0x0632,
- KSC_5601_87 = 0x0640,
- KSC_5601_92_Johab = 0x0641,
- CNS_11643_92_P1 = 0x0651,
- CNS_11643_92_P2 = 0x0652,
- CNS_11643_92_P3 = 0x0653,
- ISO_2022_JP = 0x0820,
- ISO_2022_JP_2 = 0x0821,
- ISO_2022_JP_1 = 0x0822,
- ISO_2022_JP_3 = 0x0823,
- ISO_2022_CN = 0x0830,
- ISO_2022_CN_EXT = 0x0831,
- ISO_2022_KR = 0x0840,
- EUC_JP = 0x0920,
- EUC_CN = 0x0930,
- EUC_TW = 0x0931,
- EUC_KR = 0x0940,
- ShiftJIS = 0x0A01,
- KOI8_R = 0x0A02,
- Big5 = 0x0A03,
- MacRomanLatin1 = 0x0A04,
- HZ_GB_2312 = 0x0A05,
- Big5_HKSCS_1999 = 0x0A06,
- VISCII = 0x0A07,
- KOI8_U = 0x0A08,
- Big5_E = 0x0A09,
- NextStepJapanese = 0x0B02,
- EBCDIC_US = 0x0C01,
- EBCDIC_CP037 = 0x0C02,
- UTF7 = 0x04000100,
- UTF7_IMAP = 0x0A10,
- ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
+ MacJapanese = 1,
+ MacChineseTrad = 2,
+ MacKorean = 3,
+ MacArabic = 4,
+ MacHebrew = 5,
+ MacGreek = 6,
+ MacCyrillic = 7,
+ MacDevanagari = 9,
+ MacGurmukhi = 10,
+ MacGujarati = 11,
+ MacOriya = 12,
+ MacBengali = 13,
+ MacTamil = 14,
+ MacTelugu = 15,
+ MacKannada = 16,
+ MacMalayalam = 17,
+ MacSinhalese = 18,
+ MacBurmese = 19,
+ MacKhmer = 20,
+ MacThai = 21,
+ MacLaotian = 22,
+ MacGeorgian = 23,
+ MacArmenian = 24,
+ MacChineseSimp = 25,
+ MacTibetan = 26,
+ MacMongolian = 27,
+ MacEthiopic = 28,
+ MacCentralEurRoman = 29,
+ MacVietnamese = 30,
+ MacExtArabic = 31,
+ MacSymbol = 33,
+ MacDingbats = 34,
+ MacTurkish = 35,
+ MacCroatian = 36,
+ MacIcelandic = 37,
+ MacRomanian = 38,
+ MacCeltic = 39,
+ MacGaelic = 40,
+ MacFarsi = 0x8C,
+ MacUkrainian = 0x98,
+ MacInuit = 0xEC,
+ MacVT100 = 0xFC,
+ MacHFS = 0xFF,
+ ISOLatin2 = 0x0202,
+ ISOLatin3 = 0x0203,
+ ISOLatin4 = 0x0204,
+ ISOLatinCyrillic = 0x0205,
+ ISOLatinArabic = 0x0206,
+ ISOLatinGreek = 0x0207,
+ ISOLatinHebrew = 0x0208,
+ ISOLatin5 = 0x0209,
+ ISOLatin6 = 0x020A,
+ ISOLatinThai = 0x020B,
+ ISOLatin7 = 0x020D,
+ ISOLatin8 = 0x020E,
+ ISOLatin9 = 0x020F,
+ ISOLatin10 = 0x0210,
+ DOSLatinUS = 0x0400,
+ DOSGreek = 0x0405,
+ DOSBalticRim = 0x0406,
+ DOSLatin1 = 0x0410,
+ DOSGreek1 = 0x0411,
+ DOSLatin2 = 0x0412,
+ DOSCyrillic = 0x0413,
+ DOSTurkish = 0x0414,
+ DOSPortuguese = 0x0415,
+ DOSIcelandic = 0x0416,
+ DOSHebrew = 0x0417,
+ DOSCanadianFrench = 0x0418,
+ DOSArabic = 0x0419,
+ DOSNordic = 0x041A,
+ DOSRussian = 0x041B,
+ DOSGreek2 = 0x041C,
+ DOSThai = 0x041D,
+ DOSJapanese = 0x0420,
+ DOSChineseSimplif = 0x0421,
+ DOSKorean = 0x0422,
+ DOSChineseTrad = 0x0423,
+ WindowsLatin2 = 0x0501,
+ WindowsCyrillic = 0x0502,
+ WindowsGreek = 0x0503,
+ WindowsLatin5 = 0x0504,
+ WindowsHebrew = 0x0505,
+ WindowsArabic = 0x0506,
+ WindowsBalticRim = 0x0507,
+ WindowsVietnamese = 0x0508,
+ WindowsKoreanJohab = 0x0510,
+ ANSEL = 0x0601,
+ JIS_X0201_76 = 0x0620,
+ JIS_X0208_83 = 0x0621,
+ JIS_X0208_90 = 0x0622,
+ JIS_X0212_90 = 0x0623,
+ JIS_C6226_78 = 0x0624,
+ ShiftJIS_X0213 = 0x0628,
+ ShiftJIS_X0213_MenKuTen = 0x0629,
+ GB_2312_80 = 0x0630,
+ GBK_95 = 0x0631,
+ GB_18030_2000 = 0x0632,
+ KSC_5601_87 = 0x0640,
+ KSC_5601_92_Johab = 0x0641,
+ CNS_11643_92_P1 = 0x0651,
+ CNS_11643_92_P2 = 0x0652,
+ CNS_11643_92_P3 = 0x0653,
+ ISO_2022_JP = 0x0820,
+ ISO_2022_JP_2 = 0x0821,
+ ISO_2022_JP_1 = 0x0822,
+ ISO_2022_JP_3 = 0x0823,
+ ISO_2022_CN = 0x0830,
+ ISO_2022_CN_EXT = 0x0831,
+ ISO_2022_KR = 0x0840,
+ EUC_JP = 0x0920,
+ EUC_CN = 0x0930,
+ EUC_TW = 0x0931,
+ EUC_KR = 0x0940,
+ ShiftJIS = 0x0A01,
+ KOI8_R = 0x0A02,
+ Big5 = 0x0A03,
+ MacRomanLatin1 = 0x0A04,
+ HZ_GB_2312 = 0x0A05,
+ Big5_HKSCS_1999 = 0x0A06,
+ VISCII = 0x0A07,
+ KOI8_U = 0x0A08,
+ Big5_E = 0x0A09,
+ NextStepJapanese = 0x0B02,
+ EBCDIC_US = 0x0C01,
+ EBCDIC_CP037 = 0x0C02,
+ UTF7 = 0x04000100,
+ UTF7_IMAP = 0x0A10,
+ ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
}
-@(link_prefix = "CF", default_calling_convention = "c")
+@(link_prefix="CF", default_calling_convention="c")
foreign CoreFoundation {
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 ---
@@ -181,23 +179,16 @@ foreign CoreFoundation {
STR :: StringMakeConstantString
-StringCopyToOdinString :: proc(
- theString: String,
- allocator := context.allocator,
-) -> (
- str: string,
- ok: bool,
-) #optional_ok {
+StringCopyToOdinString :: proc(theString: String, allocator := context.allocator) -> (str: string, ok: bool) #optional_ok {
length := StringGetLength(theString)
max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8))
buf, err := make([]byte, max, allocator)
- if err != nil { return }
-
- raw_str := runtime.Raw_String {
- data = raw_data(buf),
+ if err != nil {
+ return
}
- StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), max, (^Index)(&raw_str.len))
- return transmute(string)raw_str, true
+ n: Index
+ StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), Index(len(buf)), &n)
+ return string(buf[:n]), true
}
diff --git a/core/sys/darwin/Foundation/NSApplication.odin b/core/sys/darwin/Foundation/NSApplication.odin
index 482221cdf..7191f6d07 100644
--- a/core/sys/darwin/Foundation/NSApplication.odin
+++ b/core/sys/darwin/Foundation/NSApplication.odin
@@ -79,7 +79,10 @@ Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolic
return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy)
}
-@(deprecated="Use NSApplication method activate instead.")
+// NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.)
+// and has no clear alternative although `activate` is what Apple tells you to use,
+// that does not work the same way.
+// @(deprecated="Use NSApplication method activate instead.")
@(objc_type=Application, objc_name="activateIgnoringOtherApps")
Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
diff --git a/core/sys/darwin/Foundation/NSEvent.odin b/core/sys/darwin/Foundation/NSEvent.odin
index f20afd3ab..548c5c172 100644
--- a/core/sys/darwin/Foundation/NSEvent.odin
+++ b/core/sys/darwin/Foundation/NSEvent.odin
@@ -5,8 +5,8 @@ Event :: struct {using _: Object}
-EventMask :: distinct bit_set[EventType; UInteger]
-EventMaskAny :: ~EventMask{}
+EventMask :: distinct bit_set[EventType; UInteger]
+EventMaskAny :: transmute(EventMask)(max(UInteger))
when size_of(UInteger) == 4 {
// We don't support a 32-bit darwin system but this is mostly to shut up the type checker for the time being
diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin
index b4918b3fb..a10b33fc0 100644
--- a/core/sys/darwin/Foundation/NSString.odin
+++ b/core/sys/darwin/Foundation/NSString.odin
@@ -58,7 +58,10 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
@(link_prefix="NS", default_calling_convention="c")
foreign Foundation {
- StringFromClass :: proc(cls: Class) -> ^String ---
+ StringFromClass :: proc(cls: Class) -> ^String ---
+ ClassFromString :: proc(str: ^String) -> Class ---
+ StringFromSelector :: proc(selector: SEL) -> ^String ---
+ SelectorFromString :: proc(str: ^String) -> SEL ---
}
@(objc_type=String, objc_name="alloc", objc_is_class_method=true)
diff --git a/core/sys/darwin/Foundation/objc.odin b/core/sys/darwin/Foundation/objc.odin
index 51cfee444..82d6199ce 100644
--- a/core/sys/darwin/Foundation/objc.odin
+++ b/core/sys/darwin/Foundation/objc.odin
@@ -9,24 +9,85 @@ import "core:c"
IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id
+@(default_calling_convention="c")
foreign Foundation {
- objc_getMetaClass :: proc "c" (name: cstring) -> id ---
- objc_lookUpClass :: proc "c" (name: cstring) -> Class ---
- objc_allocateClassPair :: proc "c" (superclass : Class, name : cstring, extraBytes : c.size_t) -> Class ---
- objc_registerClassPair :: proc "c" (cls : Class) ---
-
- sel_registerName :: proc "c" (name: cstring) -> SEL ---
-
- class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
- class_getInstanceMethod :: proc "c" (cls: Class, name: SEL) -> Method ---
- class_createInstance :: proc "c" (cls: Class, extraBytes: c.size_t) -> id ---
-
- method_setImplementation :: proc "c" (method: Method, imp: IMP) ---
-
- object_getClass :: proc "c" (obj: id) -> Class ---
- object_setClass :: proc "c" (obj: id, cls: Class) -> Class ---
- object_getClassName :: proc "c" (obj: id) -> cstring ---
- object_getIndexedIvars :: proc "c" (obj: id) -> rawptr ---
+ objc_getMetaClass :: proc(name: cstring) -> id ---
+ objc_lookUpClass :: proc(name: cstring) -> Class ---
+ objc_allocateClassPair :: proc(superclass: Class, name: cstring, extraBytes: c.size_t) -> Class ---
+ objc_registerClassPair :: proc(cls: Class) ---
+ objc_disposeClassPair :: proc(cls: Class) ---
+ objc_duplicateClass :: proc(original: Class, name: cstring, extraBytes: c.size_t) -> Class ---
+ objc_getProtocol :: proc(name: cstring) -> ^Protocol ---
+ objc_copyProtocolList :: proc(outCount: ^uint) -> [^]^Protocol ---
+ objc_constructInstance :: proc(cls: Class, bytes: rawptr) -> id ---
+ objc_destructInstance :: proc(obj: id) -> rawptr ---
+ objc_getClassList :: proc(buffer: [^]Class, bufferCount: int) -> int ---
+ objc_copyClassList :: proc(outCount: ^uint) -> [^]Class ---
+ objc_getRequiredClass :: proc(name: cstring) -> Class ---
+ objc_setAssociatedObject :: proc(object: id, key: rawptr, value: id, policy: objc_AssociationPolicy) ---
+ objc_getAssociatedObject :: proc(object: id, key: rawptr) -> id ---
+ objc_removeAssociatedObjects :: proc(object: id) ---
+
+ sel_registerName :: proc(name: cstring) -> SEL ---
+ sel_getName :: proc(sel: SEL) -> cstring ---
+ sel_isEqual :: proc(lhs, rhs: SEL) -> BOOL ---
+
+ class_addMethod :: proc(cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
+ class_getInstanceMethod :: proc(cls: Class, name: SEL) -> Method ---
+ class_getClassMethod :: proc(cls: Class, name: SEL) -> Method ---
+ class_copyMethodList :: proc(cls: Class, outCount: ^uint) -> [^]Method ---
+ class_createInstance :: proc(cls: Class, extraBytes: c.size_t) -> id ---
+ class_replaceMethod :: proc(cls: Class, name: SEL, imp: IMP, types: cstring) -> IMP ---
+ class_getMethodImplementation :: proc(cls: Class, name: SEL) -> IMP ---
+ class_getSuperclass :: proc(cls: Class) -> Class ---
+ class_getName :: proc(cls: Class) -> cstring ---
+ class_isMetaClass :: proc(cls: Class) -> BOOL ---
+ class_addProtocol :: proc(cls: Class, protocol: ^Protocol) -> BOOL ---
+ class_getVersion :: proc(cls: Class) -> c.int ---
+ class_setVersion :: proc(cls: Class, version: c.int) ---
+ class_getProperty :: proc(cls: Class, name: cstring) -> objc_property_t ---
+ class_addProperty :: proc(cls: Class, name: cstring, attributes: [^]objc_property_attribute_t, attributeCount: uint) -> BOOL ---
+ class_replaceProperty :: proc(cls: Class, name: cstring, attributes: [^]objc_property_attribute_t, attributeCount: uint) ---
+ class_copyPropertyList :: proc(cls: Class, outCount: ^uint) -> [^]objc_property_t ---
+ class_conformsToProtocol :: proc(cls: Class, protocol: ^Protocol) -> BOOL ---
+ class_copyProtocolList :: proc(cls: Class, outCount: ^uint) -> [^]^Protocol ---
+ class_respondsToSelector :: proc(cls: Class, sel: SEL) -> BOOL ---
+ class_getClassVariable :: proc(cls: Class, name: cstring) -> Ivar ---
+ class_getInstanceVariable :: proc(cls: Class, name: cstring) -> Ivar ---
+ class_addIvar :: proc(cls: Class, name: cstring, size: c.size_t, alignment: u8, types: cstring) -> BOOL ---
+ class_copyIvarList :: proc(cls: Class, outCount: ^uint) -> [^]Ivar ---
+ class_getInstanceSize :: proc(cls: Class) -> c.size_t ---
+
+ property_getName :: proc(property: objc_property_t) -> cstring ---
+ property_getAttributes :: proc(property: objc_property_t) -> cstring ---
+ property_copyAttributeList :: proc(property: objc_property_t, outCount: ^uint) -> [^]objc_property_attribute_t ---
+ property_copyAttributeValue :: proc(property: objc_property_t, attributeName: cstring) -> cstring ---
+
+ protocol_conformsToProtocol :: proc(proto: ^Protocol, other: ^Protocol) -> BOOL ---
+ protocol_isEqual :: proc(proto: ^Protocol, other: ^Protocol) -> BOOL ---
+ protocol_getName :: proc(proto: ^Protocol) -> cstring ---
+
+ method_getImplementation :: proc(m: Method) -> IMP ---
+ method_setImplementation :: proc(m: Method, imp: IMP) ---
+ method_copyArgumentType :: proc(m: Method, index: uint) -> cstring ---
+ method_getReturnType :: proc(m: Method, dst: cstring, dst_len: c.size_t) ---
+ method_getNumberOfArguments :: proc(m: Method) -> uint ---
+ method_getArgumentType :: proc(m: Method, index: uint, dst: cstring, dst_len: c.size_t) ---
+
+ object_getClass :: proc(obj: id) -> Class ---
+ object_setClass :: proc(obj: id, cls: Class) -> Class ---
+ object_copy :: proc(obj: id, size: c.size_t) -> id ---
+ object_dispose :: proc(obj: id) -> id ---
+ object_getClassName :: proc(obj: id) -> cstring ---
+ object_getIndexedIvars :: proc(obj: id) -> rawptr ---
+ object_getInstanceVariable :: proc(obj: id, name: cstring, outValue: rawptr) -> Ivar ---
+ object_setInstanceVariable :: proc(obj: id, name: cstring, value: rawptr) -> Ivar ---
+ object_getIvar :: proc(obj: id, ivar: Ivar) -> id ---
+ object_setIvar :: proc(obj: id, ivar: Ivar, value: id) ---
+
+ ivar_getName :: proc(v: Ivar) -> cstring ---
+ ivar_getTypeEncoding :: proc(v: Ivar) -> cstring ---
+ ivar_getOffset :: proc(v: Ivar) -> c.ptrdiff_t ---
}
@@ -47,7 +108,17 @@ objc_method :: struct {
}
objc_method_list :: struct {}
+objc_property :: struct{}
+objc_property_t :: ^objc_property
+
+objc_property_attribute_t :: struct {
+ name: cstring,
+ value: cstring,
+}
+
objc_ivar :: struct {}
+Ivar :: ^objc_ivar
+
objc_ivar_list :: struct {}
objc_cache :: struct {
@@ -85,3 +156,11 @@ objc_class_internals :: struct {
protocols: rawptr,
}
+
+objc_AssociationPolicy :: enum c.uintptr_t {
+ Assign = 0,
+ Retain_Nonatomic = 1,
+ Copy_Nonatomic = 3,
+ Retain = 01401,
+ Copy = 01403,
+}
diff --git a/core/sys/darwin/darwin.odin b/core/sys/darwin/darwin.odin
index ddd25a76c..d109f5544 100644
--- a/core/sys/darwin/darwin.odin
+++ b/core/sys/darwin/darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package darwin
import "core:c"
diff --git a/core/sys/darwin/sync.odin b/core/sys/darwin/sync.odin
index 121d3edef..58fc7c9e4 100644
--- a/core/sys/darwin/sync.odin
+++ b/core/sys/darwin/sync.odin
@@ -5,6 +5,7 @@ foreign import system "system:System.framework"
// #define OS_WAIT_ON_ADDR_AVAILABILITY \
// __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
when ODIN_OS == .Darwin {
+
when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 17_04_00 {
WAIT_ON_ADDRESS_AVAILABLE :: true
} else when ODIN_MINIMUM_OS_VERSION >= 14_04_00 {
@@ -12,8 +13,18 @@ when ODIN_OS == .Darwin {
} else {
WAIT_ON_ADDRESS_AVAILABLE :: false
}
+
+ when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 14_00_00 {
+ ULOCK_WAIT_2_AVAILABLE :: true
+ } else when ODIN_MINIMUM_OS_VERSION >= 11_00_00 {
+ ULOCK_WAIT_2_AVAILABLE :: true
+ } else {
+ ULOCK_WAIT_2_AVAILABLE :: false
+ }
+
} else {
WAIT_ON_ADDRESS_AVAILABLE :: false
+ ULOCK_WAIT_2_AVAILABLE :: false
}
os_sync_wait_on_address_flag :: enum u32 {
diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin
index a641a4be9..ae8373f99 100644
--- a/core/sys/darwin/xnu_system_call_helpers.odin
+++ b/core/sys/darwin/xnu_system_call_helpers.odin
@@ -15,9 +15,9 @@ sys_write_string :: proc (fd: c.int, message: string) -> bool {
Offset_From :: enum c.int {
SEEK_SET = 0, // the offset is set to offset bytes.
SEEK_CUR = 1, // the offset is set to its current location plus offset bytes.
- SEEK_END = 2, // the offset is set to the size of the file plus offset bytes.
- SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset.
- SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset.
+ SEEK_END = 2, // the offset is set to the size of the file plus offset bytes.
+ SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset.
+ SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset.
}
Open_Flags_Enum :: enum u8 {
diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin
index 30faf86be..1188091a9 100644
--- a/core/sys/darwin/xnu_system_call_wrappers.odin
+++ b/core/sys/darwin/xnu_system_call_wrappers.odin
@@ -192,43 +192,43 @@ _STRUCT_TIMEVAL :: struct {
/* pwd.h */
_Password_Entry :: struct {
- pw_name: cstring, /* username */
- pw_passwd: cstring, /* user password */
- pw_uid: i32, /* user ID */
- pw_gid: i32, /* group ID */
+ pw_name: cstring, /* username */
+ pw_passwd: cstring, /* user password */
+ pw_uid: i32, /* user ID */
+ pw_gid: i32, /* group ID */
pw_change: u64, /* password change time */
pw_class: cstring, /* user access class */
- pw_gecos: cstring, /* full user name */
- pw_dir: cstring, /* home directory */
- pw_shell: cstring, /* shell program */
+ pw_gecos: cstring, /* full user name */
+ pw_dir: cstring, /* home directory */
+ pw_shell: cstring, /* shell program */
pw_expire: u64, /* account expiration */
pw_fields: i32, /* filled fields */
}
/* processinfo.h */
_Proc_Bsdinfo :: struct {
- pbi_flags: u32, /* if is 64bit; emulated etc */
- pbi_status: u32,
- pbi_xstatus: u32,
- pbi_pid: u32,
- pbi_ppid: u32,
- pbi_uid: u32,
- pbi_gid: u32,
- pbi_ruid: u32,
- pbi_rgid: u32,
- pbi_svuid: u32,
- pbi_svgid: u32,
- res: u32,
- pbi_comm: [DARWIN_MAXCOMLEN]u8,
- pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
- pbi_nfiles: u32,
- pbi_pgid: u32,
- pbi_pjobc: u32,
- e_tdev: u32, /* controlling tty dev */
- e_tpgid: u32, /* tty process group id */
- pbi_nice: i32,
- pbi_start_tvsec: u64,
- pbi_start_tvusec: u64,
+ pbi_flags: u32, /* if is 64bit; emulated etc */
+ pbi_status: u32,
+ pbi_xstatus: u32,
+ pbi_pid: u32,
+ pbi_ppid: u32,
+ pbi_uid: u32,
+ pbi_gid: u32,
+ pbi_ruid: u32,
+ pbi_rgid: u32,
+ pbi_svuid: u32,
+ pbi_svgid: u32,
+ res: u32,
+ pbi_comm: [DARWIN_MAXCOMLEN]u8,
+ pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
+ pbi_nfiles: u32,
+ pbi_pgid: u32,
+ pbi_pjobc: u32,
+ e_tdev: u32, /* controlling tty dev */
+ e_tpgid: u32, /* tty process group id */
+ pbi_nice: i32,
+ pbi_start_tvsec: u64,
+ pbi_start_tvusec: u64,
}
/*--==========================================================================--*/
diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin
index 4a79bd56c..83b51138a 100644
--- a/core/sys/freebsd/syscalls.odin
+++ b/core/sys/freebsd/syscalls.odin
@@ -14,12 +14,16 @@ import "core:c"
// FreeBSD 15 syscall numbers
// See: https://alfonsosiciliano.gitlab.io/posts/2023-08-28-freebsd-15-system-calls.html
+SYS_read : uintptr : 3
+SYS_write : uintptr : 4
SYS_open : uintptr : 5
SYS_close : uintptr : 6
SYS_getpid : uintptr : 20
SYS_recvfrom : uintptr : 29
SYS_accept : uintptr : 30
+SYS_getsockname: uintptr : 32
SYS_fcntl : uintptr : 92
+SYS_fsync : uintptr : 95
SYS_socket : uintptr : 97
SYS_connect : uintptr : 98
SYS_bind : uintptr : 104
@@ -29,12 +33,46 @@ SYS_shutdown : uintptr : 134
SYS_setsockopt : uintptr : 105
SYS_sysctl : uintptr : 202
SYS__umtx_op : uintptr : 454
+SYS_pread : uintptr : 475
+SYS_pwrite : uintptr : 476
SYS_accept4 : uintptr : 541
//
// Odin syscall wrappers
//
+// Read input.
+//
+// The read() function appeared in Version 1 AT&T UNIX.
+read :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_read,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf))
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
+// Write output.
+//
+// The write() function appeared in Version 1 AT&T UNIX.
+write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pwrite,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf))
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
// Open or create a file for reading, writing or executing.
//
// The open() function appeared in Version 1 AT&T UNIX.
@@ -164,6 +202,36 @@ accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) {
accept :: proc { accept_T, accept_nil }
+// Get socket name.
+//
+// The getsockname() system call appeared in 4.2BSD.
+getsockname :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno {
+ // sockaddr must contain a valid pointer, or this will segfault because
+ // we're telling the syscall that there's memory available to write to.
+ addrlen: socklen_t = size_of(T)
+
+ result, ok := intrinsics.syscall_bsd(SYS_getsockname,
+ cast(uintptr)s,
+ cast(uintptr)sockaddr,
+ cast(uintptr)&addrlen)
+
+ if !ok {
+ return cast(Errno)result
+ }
+
+ return nil
+}
+
+// Synchronize changes to a file.
+//
+// The fsync() system call appeared in 4.2BSD.
+fsync :: proc "contextless" (fd: Fd) -> Errno {
+ result, _ := intrinsics.syscall_bsd(SYS_fsync,
+ cast(uintptr)fd)
+
+ return cast(Errno)result
+}
+
// File control.
//
// The fcntl() system call appeared in 4.2BSD.
@@ -469,6 +537,46 @@ _umtx_op :: proc "contextless" (obj: rawptr, op: Userland_Mutex_Operation, val:
return cast(Errno)result
}
+// Read input without modifying the file pointer.
+//
+// The pread() function appeared in AT&T System V Release 4 UNIX.
+pread :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pread,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf),
+ cast(uintptr)offset)
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
+// Write output without modifying the file pointer.
+//
+// The pwrite() function appeared in AT&T System V Release 4 UNIX.
+//
+// BUGS
+//
+// The pwrite() system call appends the file without changing the file
+// offset if O_APPEND is set, contrary to IEEE Std 1003.1-2008 (“POSIX.1”)
+// where pwrite() writes into offset regardless of whether O_APPEND is set.
+pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pwrite,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf),
+ cast(uintptr)offset)
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
// Accept a connection on a socket.
//
// The accept4() system call appeared in FreeBSD 10.0.
diff --git a/core/sys/freebsd/types.odin b/core/sys/freebsd/types.odin
index a13961a47..37e8abf68 100644
--- a/core/sys/freebsd/types.odin
+++ b/core/sys/freebsd/types.odin
@@ -695,12 +695,12 @@ Record_Lock_Flag :: enum c.int {
// struct flock
File_Lock :: struct {
- start: off_t, /* starting offset */
- len: off_t, /* len = 0 means until end of file */
- pid: pid_t, /* lock owner */
- type: Record_Lock_Flag, /* lock type: read/write, etc. */
- whence: c.short, /* type of l_start */
- sysid: c.int, /* remote system id or zero for local */
+ start: off_t, /* starting offset */
+ len: off_t, /* len = 0 means until end of file */
+ pid: pid_t, /* lock owner */
+ type: Record_Lock_Flag, /* lock type: read/write, etc. */
+ whence: c.short, /* type of l_start */
+ sysid: c.int, /* remote system id or zero for local */
}
/*
diff --git a/core/sys/haiku/errors.odin b/core/sys/haiku/errors.odin
index 023045001..febe647ea 100644
--- a/core/sys/haiku/errors.odin
+++ b/core/sys/haiku/errors.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/find_directory.odin b/core/sys/haiku/find_directory.odin
index 103e677d7..758c4dff4 100644
--- a/core/sys/haiku/find_directory.odin
+++ b/core/sys/haiku/find_directory.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/os.odin b/core/sys/haiku/os.odin
index 883072c2d..6ab3ef573 100644
--- a/core/sys/haiku/os.odin
+++ b/core/sys/haiku/os.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/types.odin b/core/sys/haiku/types.odin
index 0440d5a98..47755b0b7 100644
--- a/core/sys/haiku/types.odin
+++ b/core/sys/haiku/types.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin
index aa4bb368a..960e55a56 100644
--- a/core/sys/info/cpu_arm.odin
+++ b/core/sys/info/cpu_arm.odin
@@ -1,4 +1,4 @@
-//+build arm32, arm64
+#+build arm32, arm64
package sysinfo
import "core:sys/unix"
diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin
index 73d4c15e7..d6fa98507 100644
--- a/core/sys/info/cpu_intel.odin
+++ b/core/sys/info/cpu_intel.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package sysinfo
import "base:intrinsics"
diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin
index dcc252971..6408decb7 100644
--- a/core/sys/info/cpu_linux_arm.odin
+++ b/core/sys/info/cpu_linux_arm.odin
@@ -1,5 +1,5 @@
-//+build arm32, arm64
-//+build linux
+#+build arm32, arm64
+#+build linux
package sysinfo
import "core:sys/linux"
diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin
index 0f109e7ba..84f6134d4 100644
--- a/core/sys/info/cpu_linux_riscv64.odin
+++ b/core/sys/info/cpu_linux_riscv64.odin
@@ -1,5 +1,5 @@
-//+build riscv64
-//+build linux
+#+build riscv64
+#+build linux
package sysinfo
import "base:intrinsics"
@@ -8,35 +8,102 @@ import "core:sys/linux"
@(init, private)
init_cpu_features :: proc() {
- fd, err := linux.open("/proc/self/auxv", {})
- if err != .NONE { return }
- defer linux.close(fd)
-
- // This is probably enough right?
- buf: [4096]byte
- n, rerr := linux.read(fd, buf[:])
- if rerr != .NONE || n == 0 { return }
-
- ulong :: u64
- AT_HWCAP :: 16
-
- // TODO: using these we could get more information than just the basics.
- // AT_HWCAP2 :: 26
- // AT_HWCAP3 :: 29
- // AT_HWCAP4 :: 30
-
- auxv := buf[:n]
- for len(auxv) >= size_of(ulong)*2 {
- key := intrinsics.unaligned_load((^ulong)(&auxv[0]))
- val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)]))
- auxv = auxv[2*size_of(ulong):]
-
- if key != AT_HWCAP {
- continue
+ _features: CPU_Features
+ defer cpu_features = _features
+
+ HWCAP_Bits :: enum u64 {
+ I = 'I' - 'A',
+ M = 'M' - 'A',
+ A = 'A' - 'A',
+ F = 'F' - 'A',
+ D = 'D' - 'A',
+ C = 'C' - 'A',
+ V = 'V' - 'A',
+ }
+ HWCAP :: bit_set[HWCAP_Bits; u64]
+
+ // Read HWCAP for base extensions, we can get this info through hwprobe too but that is Linux 6.4+ only.
+ {
+ fd, err := linux.open("/proc/self/auxv", {})
+ if err != .NONE { return }
+ defer linux.close(fd)
+
+ // This is probably enough right?
+ buf: [4096]byte
+ n, rerr := linux.read(fd, buf[:])
+ if rerr != .NONE || n == 0 { return }
+
+ ulong :: u64
+ AT_HWCAP :: 16
+
+ auxv := buf[:n]
+ for len(auxv) >= size_of(ulong)*2 {
+ key := intrinsics.unaligned_load((^ulong)(&auxv[0]))
+ val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)]))
+ auxv = auxv[2*size_of(ulong):]
+
+ if key != AT_HWCAP {
+ continue
+ }
+
+ cap := transmute(HWCAP)(val)
+ if .I in cap {
+ _features += { .I }
+ }
+ if .M in cap {
+ _features += { .M }
+ }
+ if .A in cap {
+ _features += { .A }
+ }
+ if .F in cap {
+ _features += { .F }
+ }
+ if .D in cap {
+ _features += { .D }
+ }
+ if .C in cap {
+ _features += { .C }
+ }
+ if .V in cap {
+ _features += { .V }
+ }
+ break
}
+ }
- cpu_features = transmute(CPU_Features)(val)
- break
+ // hwprobe for other features.
+ {
+ pairs := []linux.RISCV_HWProbe{
+ { key = .IMA_EXT_0 },
+ { key = .CPUPERF_0 },
+ { key = .MISALIGNED_SCALAR_PERF },
+ }
+ err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
+ if err != nil {
+ assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
+ return
+ }
+
+ assert(pairs[0].key == .IMA_EXT_0)
+ exts := pairs[0].value.ima_ext_0
+ exts -= { .FD, .C, .V }
+ _features += transmute(CPU_Features)exts
+
+ if pairs[2].key == .MISALIGNED_SCALAR_PERF {
+ if pairs[2].value.misaligned_scalar_perf == .FAST {
+ _features += { .Misaligned_Supported, .Misaligned_Fast }
+ } else if pairs[2].value.misaligned_scalar_perf != .UNSUPPORTED {
+ _features += { .Misaligned_Supported }
+ }
+ } else {
+ assert(pairs[1].key == .CPUPERF_0)
+ if .FAST in pairs[1].value.cpu_perf_0 {
+ _features += { .Misaligned_Supported, .Misaligned_Fast }
+ } else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
+ _features += { .Misaligned_Supported }
+ }
+ }
}
}
diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin
index 754110911..c3319c48c 100644
--- a/core/sys/info/cpu_riscv64.odin
+++ b/core/sys/info/cpu_riscv64.odin
@@ -1,13 +1,97 @@
package sysinfo
CPU_Feature :: enum u64 {
- I = 'I' - 'A', // Base features, don't think this is ever not here.
- M = 'M' - 'A', // Integer multiplication and division, currently required by Odin.
- A = 'A' - 'A', // Atomics.
- F = 'F' - 'A', // Single precision floating point, currently required by Odin.
- D = 'D' - 'A', // Double precision floating point, currently required by Odin.
- C = 'C' - 'A', // Compressed instructions.
- V = 'V' - 'A', // Vector operations.
+ // Bit-Manipulation ISA Extensions v1.
+ Zba = 3,
+ Zbb,
+ Zbs,
+
+ // CMOs (ratified).
+ Zicboz,
+
+ // Bit-Manipulation ISA Extensions v1.
+ Zbc,
+
+ // Scalar Crypto ISA extensions v1.
+ Zbkb,
+ Zbkc,
+ Zbkx,
+ Zknd,
+ Zkne,
+ Zknh,
+ Zksed,
+ Zksh,
+ Zkt,
+
+ // Cryptography Extensions Volume II v1.
+ Zvbb,
+ Zvbc,
+ Zvkb,
+ Zvkg,
+ Zvkned,
+ Zvknha,
+ Zvknhb,
+ Zvksed,
+ Zvksh,
+ Zvkt,
+
+ // ISA Manual v1.
+ Zfh,
+ Zfhmin,
+ Zihintntl,
+
+ // ISA manual (ratified).
+ Zvfh,
+ Zvfhmin,
+ Zfa,
+ Ztso,
+
+ // Atomic Compare-and-Swap Instructions Manual (ratified).
+ Zacas,
+ Zicond,
+
+ // ISA manual (ratified).
+ Zihintpause,
+
+ // Vector Extensions Manual v1.
+ Zve32x,
+ Zve32f,
+ Zve64x,
+ Zve64f,
+ Zve64d,
+
+ // ISA manual (ratified).
+ Zimop,
+
+ // Code Size Reduction (ratified).
+ Zca,
+ Zcb,
+ Zcd,
+ Zcf,
+
+ // ISA manual (ratified).
+ Zcmop,
+ Zawrs,
+
+ // Base features, don't think this is ever not here.
+ I,
+ // Integer multiplication and division, currently required by Odin.
+ M,
+ // Atomics.
+ A,
+ // Single precision floating point, currently required by Odin.
+ F,
+ // Double precision floating point, currently required by Odin.
+ D,
+ // Compressed instructions.
+ C,
+ // Vector operations.
+ V,
+
+ // Indicates Misaligned Scalar Loads will not trap the program.
+ Misaligned_Supported,
+ // Indicates Hardware Support for Misaligned Scalar Loads.
+ Misaligned_Fast,
}
CPU_Features :: distinct bit_set[CPU_Feature; u64]
diff --git a/core/sys/info/doc.odin b/core/sys/info/doc.odin
index 802cd9c60..b5cd62d81 100644
--- a/core/sys/info/doc.odin
+++ b/core/sys/info/doc.odin
@@ -2,6 +2,12 @@
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
+List of contributors:
+ Jeroen van Rijn: Initial implementation.
+ Laytan: ARM and RISC-V CPU feature detection.
+*/
+
+/*
Package `core:sys/info` gathers system information on:
Windows, Linux, macOS, FreeBSD & OpenBSD.
@@ -11,9 +17,10 @@ and CPU information.
On Windows, GPUs will also be enumerated using the registry.
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
-`if .aes in si.aes { ... }`
+`if .aes in info.cpu_features.? { ... }`
Example:
+ package main
import "core:fmt"
import si "core:sys/info"
diff --git a/core/sys/info/platform_bsd.odin b/core/sys/info/platform_bsd.odin
index e2273d253..6bb32cd3d 100644
--- a/core/sys/info/platform_bsd.odin
+++ b/core/sys/info/platform_bsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd, netbsd
+#+build openbsd, netbsd
package sysinfo
import sys "core:sys/unix"
diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin
index 3fd857bfe..493f038f0 100644
--- a/core/sys/info/platform_darwin.odin
+++ b/core/sys/info/platform_darwin.odin
@@ -530,6 +530,10 @@ macos_release_map: map[string]Darwin_To_Release = {
"23F79" = {{23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
"23G80" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
"23G93" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
+ "23H124" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
+
+ // MacOS Sequoia
+ "24A335" = {{24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
}
@(private)
diff --git a/core/sys/kqueue/kqueue.odin b/core/sys/kqueue/kqueue.odin
index 27d1ecaae..56be1cf7a 100644
--- a/core/sys/kqueue/kqueue.odin
+++ b/core/sys/kqueue/kqueue.odin
@@ -1,4 +1,4 @@
-//+build darwin, netbsd, openbsd, freebsd
+#+build darwin, netbsd, openbsd, freebsd
package kqueue
when ODIN_OS == .Darwin {
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
index f78891bc8..8a4a6dd7a 100644
--- a/core/sys/linux/bits.odin
+++ b/core/sys/linux/bits.odin
@@ -1839,3 +1839,87 @@ Execveat_Flags_Bits :: enum {
AT_SYMLINK_NOFOLLOW = 8,
AT_EMPTY_PATH = 12,
}
+
+RISCV_HWProbe_Key :: enum i64 {
+ UNSUPPORTED = -1,
+ MVENDORID = 0,
+ MARCHID = 1,
+ MIMPID = 2,
+ BASE_BEHAVIOR = 3,
+ IMA_EXT_0 = 4,
+ // Deprecated, try `.MISALIGNED_SCALAR_PERF` first, if that is `.UNSUPPORTED`, use this.
+ CPUPERF_0 = 5,
+ ZICBOZ_BLOCK_SIZE = 6,
+ HIGHEST_VIRT_ADDRESS = 7,
+ TIME_CSR_FREQ = 8,
+ MISALIGNED_SCALAR_PERF = 9,
+}
+
+RISCV_HWProbe_Flags_Bits :: enum {
+ WHICH_CPUS,
+}
+
+RISCV_HWProbe_Base_Behavior_Bits :: enum {
+ IMA,
+}
+
+RISCV_HWProbe_IMA_Ext_0_Bits :: enum {
+ FD,
+ C,
+ V,
+ EXT_ZBA,
+ EXT_ZBB,
+ EXT_ZBS,
+ EXT_ZICBOZ,
+ EXT_ZBC,
+ EXT_ZBKB,
+ EXT_ZBKC,
+ EXT_ZBKX,
+ EXT_ZKND,
+ EXT_ZKNE,
+ EXT_ZKNH,
+ EXT_ZKSED,
+ EXT_ZKSH,
+ EXT_ZKT,
+ EXT_ZVBB,
+ EXT_ZVBC,
+ EXT_ZVKB,
+ EXT_ZVKG,
+ EXT_ZVKNED,
+ EXT_ZVKNHA,
+ EXT_ZVKNHB,
+ EXT_ZVKSED,
+ EXT_ZVKSH,
+ EXT_ZVKT,
+ EXT_ZFH,
+ EXT_ZFHMIN,
+ EXT_ZIHINTNTL,
+ EXT_ZVFH,
+ EXT_ZVFHMIN,
+ EXT_ZFA,
+ EXT_ZTSO,
+ EXT_ZACAS,
+ EXT_ZICOND,
+ EXT_ZIHINTPAUSE,
+ EXT_ZVE32X,
+ EXT_ZVE32F,
+ EXT_ZVE64X,
+ EXT_ZVE64F,
+ EXT_ZVE64D,
+ EXT_ZIMOP,
+ EXT_ZCA,
+ EXT_ZCB,
+ EXT_ZCD,
+ EXT_ZCF,
+ EXT_ZCMOP,
+ EXT_ZAWRS,
+}
+
+RISCV_HWProbe_Misaligned_Scalar_Perf :: enum {
+ UNKNOWN,
+ EMULATED,
+ SLOW,
+ FAST,
+ UNSUPPORTED,
+}
+
diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin
index f1abbbf61..aefc1179e 100644
--- a/core/sys/linux/helpers.odin
+++ b/core/sys/linux/helpers.odin
@@ -1,5 +1,5 @@
-//+build linux
-//+no-instrumentation
+#+build linux
+#+no-instrumentation
package linux
import "base:intrinsics"
diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin
index 6e4194be7..c5894d78b 100644
--- a/core/sys/linux/sys.odin
+++ b/core/sys/linux/sys.odin
@@ -1,4 +1,4 @@
-//+no-instrumentation
+#+no-instrumentation
package linux
import "base:intrinsics"
@@ -1443,8 +1443,9 @@ ptrace_traceme :: proc "contextless" (rq: PTrace_Traceme_Type) -> (Errno) {
}
ptrace_peek :: proc "contextless" (rq: PTrace_Peek_Type, pid: Pid, addr: uintptr) -> (uint, Errno) {
- ret := syscall(SYS_ptrace, rq, pid, addr)
- return errno_unwrap(ret, uint)
+ res: uint = ---
+ ret := syscall(SYS_ptrace, rq, pid, addr, &res)
+ return res, Errno(-ret)
}
ptrace_poke :: proc "contextless" (rq: PTrace_Poke_Type, pid: Pid, addr: uintptr, data: uint) -> (Errno) {
@@ -1493,12 +1494,12 @@ ptrace_setregset :: proc "contextless" (rq: PTrace_Setregset_Type, pid: Pid, not
}
ptrace_getsiginfo :: proc "contextless" (rq: PTrace_Getsiginfo_Type, pid: Pid, si: ^Sig_Info) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, si)
+ ret := syscall(SYS_ptrace, rq, pid, si, rawptr(nil))
return Errno(-ret)
}
ptrace_peeksiginfo :: proc "contextless" (rq: PTrace_Peeksiginfo_Type, pid: Pid, si: ^Sig_Info) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, si)
+ ret := syscall(SYS_ptrace, rq, pid, si, rawptr(nil))
return Errno(-ret)
}
@@ -1518,52 +1519,52 @@ ptrace_setoptions :: proc "contextless" (rq: PTrace_Setoptions_Type, pid: Pid, o
}
ptrace_geteventmsg :: proc "contextless" (rq: PTrace_Geteventmsg_Type, pid: Pid, msg: ^uint) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, msg)
+ ret := syscall(SYS_ptrace, rq, pid, msg, rawptr(nil))
return Errno(-ret)
}
ptrace_cont :: proc "contextless" (rq: PTrace_Cont_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_singlestep :: proc "contextless" (rq: PTrace_Singlestep_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_syscall :: proc "contextless" (rq: PTrace_Syscall_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_sysemu :: proc "contextless" (rq: PTrace_Sysemu_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_sysemu_singlestep :: proc "contextless" (rq: PTrace_Sysemu_Singlestep_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_listen :: proc "contextless" (rq: PTrace_Listen_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_interrupt :: proc "contextless" (rq: PTrace_Interrupt_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_attach :: proc "contextless" (rq: PTrace_Attach_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_seize :: proc "contextless" (rq: PTrace_Seize_Type, pid: Pid, opt: PTrace_Options) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, 0, transmute(u32) opt)
+ ret := syscall(SYS_ptrace, rq, pid, 0, transmute(u32) opt, rawptr(nil))
return Errno(-ret)
}
@@ -2993,3 +2994,18 @@ epoll_pwait2 :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: ^Tim
// TODO(flysand): fchmodat2
// TODO(flysand): map_shadow_stack
+
+when ODIN_ARCH == .riscv64 {
+ /*
+ Probe for RISC-V Hardware Support.
+ Available since Linux 6.4.
+
+ TODO: cpu_set_t
+
+ See: https://docs.kernel.org/arch/riscv/hwprobe.html
+ */
+ riscv_hwprobe :: proc "contextless" (pairs: [^]RISCV_HWProbe, pair_count: uint, cpu_count: uint, cpus: rawptr /* cpu_set_t */, flags: RISCV_HWProbe_Flags) -> Errno {
+ ret := syscall(SYS_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, transmute(u32)flags)
+ return Errno(-ret)
+ }
+}
diff --git a/core/sys/linux/syscall_amd64.odin b/core/sys/linux/syscall_amd64.odin
index ee4e16280..31c8ed61c 100644
--- a/core/sys/linux/syscall_amd64.odin
+++ b/core/sys/linux/syscall_amd64.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package linux
// AMD64 uses the new way to define syscalls, i.e. one that
diff --git a/core/sys/linux/syscall_arm32.odin b/core/sys/linux/syscall_arm32.odin
index 74640a1a3..731ce36a5 100644
--- a/core/sys/linux/syscall_arm32.odin
+++ b/core/sys/linux/syscall_arm32.odin
@@ -1,4 +1,4 @@
-//+build arm32
+#+build arm32
package linux
// This file was taken and transformed from
diff --git a/core/sys/linux/syscall_arm64.odin b/core/sys/linux/syscall_arm64.odin
index 61b5a31b7..da8eb45da 100644
--- a/core/sys/linux/syscall_arm64.odin
+++ b/core/sys/linux/syscall_arm64.odin
@@ -1,4 +1,4 @@
-//+build arm64
+#+build arm64
package linux
// Syscalls for arm64 are defined using the new way, i.e. differently from
diff --git a/core/sys/linux/syscall_i386.odin b/core/sys/linux/syscall_i386.odin
index 4609fc99c..affdff02c 100644
--- a/core/sys/linux/syscall_i386.odin
+++ b/core/sys/linux/syscall_i386.odin
@@ -1,4 +1,4 @@
-//+build i386
+#+build i386
package linux
// The numbers are taken from
diff --git a/core/sys/linux/syscall_riscv64.odin b/core/sys/linux/syscall_riscv64.odin
index ce374312e..17845c5ed 100644
--- a/core/sys/linux/syscall_riscv64.odin
+++ b/core/sys/linux/syscall_riscv64.odin
@@ -1,4 +1,4 @@
-//+build riscv64
+#+build riscv64
package linux
// https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/linux-headers/include/asm-generic/unistd.h
@@ -248,6 +248,7 @@ SYS_rt_tgsigqueueinfo :: uintptr(240)
SYS_perf_event_open :: uintptr(241)
SYS_accept4 :: uintptr(242)
SYS_recvmmsg :: uintptr(243)
+SYS_riscv_hwprobe :: uintptr(258)
SYS_wait4 :: uintptr(260)
SYS_prlimit64 :: uintptr(261)
SYS_fanotify_init :: uintptr(262)
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
index 3f873f96c..0e5b8218b 100644
--- a/core/sys/linux/types.odin
+++ b/core/sys/linux/types.odin
@@ -1335,3 +1335,20 @@ EPoll_Event :: struct #packed {
Flags for execveat(2) syscall.
*/
Execveat_Flags :: bit_set[Execveat_Flags_Bits; i32]
+
+RISCV_HWProbe_Flags :: bit_set[RISCV_HWProbe_Flags_Bits; u32]
+RISCV_HWProbe_CPU_Perf_0 :: bit_set[RISCV_HWProbe_Misaligned_Scalar_Perf; u64]
+RISCV_HWProbe_Base_Behavior :: bit_set[RISCV_HWProbe_Base_Behavior_Bits; u64]
+RISCV_HWProbe_IMA_Ext_0 :: bit_set[RISCV_HWProbe_IMA_Ext_0_Bits; u64]
+
+RISCV_HWProbe :: struct {
+ // set to `.UNSUPPORTED` by the kernel if that is the case.
+ key: RISCV_HWProbe_Key,
+ value: struct #raw_union {
+ base_behavior: RISCV_HWProbe_Base_Behavior,
+ ima_ext_0: RISCV_HWProbe_IMA_Ext_0,
+ cpu_perf_0: RISCV_HWProbe_CPU_Perf_0,
+ misaligned_scalar_perf: RISCV_HWProbe_Misaligned_Scalar_Perf,
+ raw: u64,
+ },
+}
diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin
index 7a30c3bde..4f6118c80 100644
--- a/core/sys/linux/wrappers.odin
+++ b/core/sys/linux/wrappers.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package linux
/// Low 8 bits of the exit code
diff --git a/core/sys/llvm/bit_manipulation.odin b/core/sys/llvm/bit_manipulation.odin
index 39464773d..2e237dd32 100644
--- a/core/sys/llvm/bit_manipulation.odin
+++ b/core/sys/llvm/bit_manipulation.odin
@@ -1,4 +1,5 @@
// Bit Manipulation Intrinsics
+
package sys_llvm
/*
diff --git a/core/sys/llvm/code_generator.odin b/core/sys/llvm/code_generator.odin
index 7d41ed67b..6422976c5 100644
--- a/core/sys/llvm/code_generator.odin
+++ b/core/sys/llvm/code_generator.odin
@@ -1,4 +1,5 @@
// Code Generator Intrinsics
+
package sys_llvm
@(default_calling_convention="none")
diff --git a/core/sys/llvm/standard_c_library.odin b/core/sys/llvm/standard_c_library.odin
index 108d1268e..1818e8462 100644
--- a/core/sys/llvm/standard_c_library.odin
+++ b/core/sys/llvm/standard_c_library.odin
@@ -1,4 +1,5 @@
// Standard C Library Intrinsics
+
package sys_llvm
@(default_calling_convention="none")
diff --git a/core/sys/posix/time.odin b/core/sys/posix/time.odin
index 9b91c9558..5c6ebcf2f 100644
--- a/core/sys/posix/time.odin
+++ b/core/sys/posix/time.odin
@@ -13,7 +13,7 @@ when ODIN_OS == .Darwin {
foreign lib {
/*
- Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973\n\0
+ Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime_r.html ]]
*/
diff --git a/core/sys/posix/unistd.odin b/core/sys/posix/unistd.odin
index 6ed9e5d11..15dbb576f 100644
--- a/core/sys/posix/unistd.odin
+++ b/core/sys/posix/unistd.odin
@@ -112,7 +112,7 @@ foreign lib {
Return configuration-defined string values.
Its use and purpose are similar to sysconf(), but it is used where string values rather than numeric values are returned.
- Returns: 0 (setting errno) if `name` is invalid, need `buf` `len` if buf is `nil`, amount of bytes added to buf otherwise
+ Returns: 0 (setting errno) if `name` is invalid, need `buf` of `len` bytes if `buf` is `nil`, amount of bytes added to buf otherwise
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html ]]
*/
diff --git a/core/sys/unix/pthread_darwin.odin b/core/sys/unix/pthread_darwin.odin
index 378fa9309..eb2cc4c9f 100644
--- a/core/sys/unix/pthread_darwin.odin
+++ b/core/sys/unix/pthread_darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_freebsd.odin b/core/sys/unix/pthread_freebsd.odin
index 5f4dac289..38fe7db55 100644
--- a/core/sys/unix/pthread_freebsd.odin
+++ b/core/sys/unix/pthread_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_linux.odin b/core/sys/unix/pthread_linux.odin
index f4ded7464..d67add24b 100644
--- a/core/sys/unix/pthread_linux.odin
+++ b/core/sys/unix/pthread_linux.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_openbsd.odin b/core/sys/unix/pthread_openbsd.odin
index 855e7d99c..2c6d9e598 100644
--- a/core/sys/unix/pthread_openbsd.odin
+++ b/core/sys/unix/pthread_openbsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd
+#+build openbsd
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin
index 68a0859b4..43c4866ed 100644
--- a/core/sys/unix/pthread_unix.odin
+++ b/core/sys/unix/pthread_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
package unix
foreign import "system:pthread"
@@ -27,6 +27,8 @@ foreign pthread {
pthread_equal :: proc(a, b: pthread_t) -> b32 ---
+ pthread_detach :: proc(t: pthread_t) -> c.int ---
+
sched_get_priority_min :: proc(policy: c.int) -> c.int ---
sched_get_priority_max :: proc(policy: c.int) -> c.int ---
diff --git a/core/sys/unix/sysctl_darwin.odin b/core/sys/unix/sysctl_darwin.odin
index 92222bdfe..32dd720b0 100644
--- a/core/sys/unix/sysctl_darwin.odin
+++ b/core/sys/unix/sysctl_darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package unix
import "base:intrinsics"
diff --git a/core/sys/unix/sysctl_freebsd.odin b/core/sys/unix/sysctl_freebsd.odin
index 8ca40ef1b..f5fee6c6c 100644
--- a/core/sys/unix/sysctl_freebsd.odin
+++ b/core/sys/unix/sysctl_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package unix
import "base:intrinsics"
diff --git a/core/sys/unix/sysctl_openbsd.odin b/core/sys/unix/sysctl_openbsd.odin
index b93e8f9bd..49c9b6336 100644
--- a/core/sys/unix/sysctl_openbsd.odin
+++ b/core/sys/unix/sysctl_openbsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd
+#+build openbsd
package unix
import "core:c"
diff --git a/core/sys/valgrind/callgrind.odin b/core/sys/valgrind/callgrind.odin
index b1ba8c6e9..5cd58753a 100644
--- a/core/sys/valgrind/callgrind.odin
+++ b/core/sys/valgrind/callgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/helgrind.odin b/core/sys/valgrind/helgrind.odin
index 2f0114522..3f5e7a531 100644
--- a/core/sys/valgrind/helgrind.odin
+++ b/core/sys/valgrind/helgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/memcheck.odin b/core/sys/valgrind/memcheck.odin
index dfbe4c3be..bc77444be 100644
--- a/core/sys/valgrind/memcheck.odin
+++ b/core/sys/valgrind/memcheck.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/valgrind.odin b/core/sys/valgrind/valgrind.odin
index d0c46af53..b5c71664f 100644
--- a/core/sys/valgrind/valgrind.odin
+++ b/core/sys/valgrind/valgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/wasm/README.md b/core/sys/wasm/README.md
new file mode 100644
index 000000000..1aaeaa429
--- /dev/null
+++ b/core/sys/wasm/README.md
@@ -0,0 +1,15 @@
+# WASM on the Web
+
+This directory is for use when targeting the `js_wasm32` target and the packages that rely on it.
+
+The `js_wasm32` target assumes that the WASM output will be ran within a web browser rather than a standalone VM. In the VM cases, either `wasi_wasm32` or `freestanding_wasm32` should be used accordingly.
+
+## Example for `js_wasm32`
+
+```html
+<!-- Copy `core:sys/wasm/js/odin.js` into your web server -->
+<script type="text/javascript" src="odin.js"></script>
+<script type="text/javascript">
+ odin.runWasm(pathToWasm, consolePreElement);
+</script>
+```
diff --git a/vendor/wasm/js/dom.odin b/core/sys/wasm/js/dom.odin
index 3a8bd0ac4..ffc58a9a3 100644
--- a/vendor/wasm/js/dom.odin
+++ b/core/sys/wasm/js/dom.odin
@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64p32
+#+build js wasm32, js wasm64p32
package wasm_js_interface
foreign import dom_lib "odin_dom"
@@ -8,9 +8,15 @@ foreign dom_lib {
get_element_value_f64 :: proc(id: string) -> f64 ---
set_element_value_f64 :: proc(id: string, value: f64) ---
+ get_element_key_f64 :: proc(id: string, key: string) -> f64 ---
+ set_element_key_f64 :: proc(id: string, key: string, value: f64) ---
+
set_element_value_string :: proc(id: string, value: string) ---
get_element_value_string_length :: proc(id: string) -> int ---
+ set_element_key_string :: proc(id: string, key: string, value: string) ---
+ get_element_key_string_length :: proc(id: string, key: string, ) -> int ---
+
device_pixel_ratio :: proc() -> f64 ---
window_set_scroll :: proc(x, y: f64) ---
@@ -24,10 +30,21 @@ get_element_value_string :: proc "contextless" (id: string, buf: []byte) -> stri
}
n := _get_element_value_string(id, buf)
return string(buf[:n])
+}
+
+get_element_key_string :: proc "contextless" (id: string, key: string, buf: []byte) -> string {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_element_key_string")
+ _get_element_key_string :: proc(id: string, key: string, buf: []byte) -> int ---
+ }
+ n := _get_element_key_string(id, key, buf)
+ return string(buf[:n])
}
+
get_element_min_max :: proc "contextless" (id: string) -> (min, max: f64) {
@(default_calling_convention="contextless")
foreign dom_lib {
@@ -73,4 +90,4 @@ window_get_scroll :: proc "contextless" () -> (x, y: f64) {
scroll: [2]f64
_window_get_scroll(&scroll)
return scroll.x, scroll.y
-}
+} \ No newline at end of file
diff --git a/vendor/wasm/js/dom_all_targets.odin b/core/sys/wasm/js/dom_all_targets.odin
index ef629b347..171deed2f 100644
--- a/vendor/wasm/js/dom_all_targets.odin
+++ b/core/sys/wasm/js/dom_all_targets.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package wasm_js_interface
import "base:runtime"
diff --git a/vendor/wasm/js/events.odin b/core/sys/wasm/js/events.odin
index 4e786e2be..905b3eba9 100644
--- a/vendor/wasm/js/events.odin
+++ b/core/sys/wasm/js/events.odin
@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64p32
+#+build js wasm32, js wasm64p32
package wasm_js_interface
foreign import dom_lib "odin_dom"
@@ -30,10 +30,12 @@ Event_Kind :: enum u32 {
Wheel,
Focus,
+ Focus_In,
+ Focus_Out,
Submit,
Blur,
Change,
- HashChange,
+ Hash_Change,
Select,
Animation_Start,
@@ -80,6 +82,9 @@ Event_Kind :: enum u32 {
Context_Menu,
+ Gamepad_Connected,
+ Gamepad_Disconnected,
+
Custom,
}
@@ -110,10 +115,12 @@ event_kind_string := [Event_Kind]string{
.Wheel = "wheel",
.Focus = "focus",
+ .Focus_In = "focusin",
+ .Focus_Out = "focusout",
.Submit = "submit",
.Blur = "blur",
.Change = "change",
- .HashChange = "hashchange",
+ .Hash_Change = "hashchange",
.Select = "select",
.Animation_Start = "animationstart",
@@ -160,6 +167,9 @@ event_kind_string := [Event_Kind]string{
.Context_Menu = "contextmenu",
+ .Gamepad_Connected = "gamepadconnected",
+ .Gamepad_Disconnected = "gamepaddisconnected",
+
.Custom = "?custom?",
}
@@ -176,9 +186,15 @@ Key_Location :: enum u8 {
Numpad = 3,
}
-KEYBOARD_MAX_KEY_SIZE :: 16
+KEYBOARD_MAX_KEY_SIZE :: 16
KEYBOARD_MAX_CODE_SIZE :: 16
+GAMEPAD_MAX_ID_SIZE :: 64
+GAMEPAD_MAX_MAPPING_SIZE :: 64
+
+GAMEPAD_MAX_BUTTONS :: 64
+GAMEPAD_MAX_AXES :: 16
+
Event_Target_Kind :: enum u32 {
Element = 0,
Document = 1,
@@ -199,6 +215,30 @@ Event_Option :: enum u8 {
}
Event_Options :: distinct bit_set[Event_Option; u8]
+Gamepad_Button :: struct {
+ value: f64,
+ pressed: bool,
+ touched: bool,
+}
+
+Gamepad_State :: struct {
+ id: string,
+ mapping: string,
+ index: int,
+ connected: bool,
+ timestamp: f64,
+
+ button_count: int,
+ axis_count: int,
+ buttons: [GAMEPAD_MAX_BUTTONS]Gamepad_Button `fmt:"v,button_count"`,
+ axes: [GAMEPAD_MAX_AXES]f64 `fmt:"v,axes_count"`,
+
+ _id_len: int `fmt:"-"`,
+ _mapping_len: int `fmt:"-"`,
+ _id_buf: [GAMEPAD_MAX_ID_SIZE]byte `fmt:"-"`,
+ _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
+}
+
Event :: struct {
kind: Event_Kind,
target_kind: Event_Target_Kind,
@@ -235,10 +275,10 @@ Event :: struct {
repeat: bool,
- _key_len: int,
- _code_len: int,
- _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
- _code_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
+ _key_len: int `fmt:"-"`,
+ _code_len: int `fmt:"-"`,
+ _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
+ _code_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
},
mouse: struct {
@@ -256,6 +296,8 @@ Event :: struct {
button: i16,
buttons: bit_set[0..<16; u16],
},
+
+ gamepad: Gamepad_State,
},
@@ -332,7 +374,18 @@ remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr
return _remove_event_listener(id, name, user_data, callback)
}
+get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_gamepad_state")
+ _get_gamepad_state :: proc(index: int, s: ^Gamepad_State) -> bool ---
+ }
+ if s == nil {
+ return false
+ }
+ return _get_gamepad_state(index, s)
+}
@(export, link_name="odin_dom_do_event_callback")
@@ -351,9 +404,13 @@ do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
init_event_raw(&event)
- if event.kind == .Key_Up || event.kind == .Key_Down || event.kind == .Key_Press {
+ #partial switch event.kind {
+ case .Key_Up, .Key_Down, .Key_Press:
event.key.key = string(event.key._key_buf[:event.key._key_len])
event.key.code = string(event.key._code_buf[:event.key._code_len])
+ case .Gamepad_Connected, .Gamepad_Disconnected:
+ event.gamepad.id = string(event.gamepad._id_buf[:event.gamepad._id_len])
+ event.gamepad.mapping = string(event.gamepad._mapping_buf[:event.gamepad._mapping_len])
}
callback(event)
diff --git a/vendor/wasm/js/events_all_targets.odin b/core/sys/wasm/js/events_all_targets.odin
index 19a004250..b7e01ca10 100644
--- a/vendor/wasm/js/events_all_targets.odin
+++ b/core/sys/wasm/js/events_all_targets.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package wasm_js_interface
@@ -284,5 +284,4 @@ add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, c
}
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
-}
-
+} \ No newline at end of file
diff --git a/vendor/wasm/js/general.odin b/core/sys/wasm/js/general.odin
index 513c60a6f..4ed2ae298 100644
--- a/vendor/wasm/js/general.odin
+++ b/core/sys/wasm/js/general.odin
@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64p32
+#+build js wasm32, js wasm64p32
package wasm_js_interface
foreign import "odin_env"
diff --git a/vendor/wasm/js/memory_all_targets.odin b/core/sys/wasm/js/memory_all_targets.odin
index e1de6a696..e80d13c0b 100644
--- a/vendor/wasm/js/memory_all_targets.odin
+++ b/core/sys/wasm/js/memory_all_targets.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package wasm_js_interface
import "core:mem"
diff --git a/vendor/wasm/js/memory_js.odin b/core/sys/wasm/js/memory_js.odin
index c513cc4a1..8232cd0c9 100644
--- a/vendor/wasm/js/memory_js.odin
+++ b/core/sys/wasm/js/memory_js.odin
@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64p32
+#+build js wasm32, js wasm64p32
package wasm_js_interface
import "core:mem"
diff --git a/vendor/wasm/js/runtime.js b/core/sys/wasm/js/odin.js
index 74ad7568e..bf002da74 100644
--- a/vendor/wasm/js/runtime.js
+++ b/core/sys/wasm/js/odin.js
@@ -108,7 +108,7 @@ class WasmMemoryInterface {
const bytes = this.loadBytes(ptr, Number(len));
return new TextDecoder().decode(bytes);
}
-
+
loadCstring(ptr) {
const start = this.loadPtr(ptr);
if (start == 0) {
@@ -1259,7 +1259,7 @@ class WebGLInterface {
};
-function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
+function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, eventQueue, event_temp) {
const MAX_INFO_CONSOLE_LINES = 512;
let infoConsoleLines = new Array();
let currentLine = {};
@@ -1377,10 +1377,8 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
info.scrollTop = info.scrollHeight;
};
- let event_temp_data = {};
-
let webglContext = new WebGLInterface(wasmMemoryInterface);
-
+
const env = {};
if (memory) {
@@ -1455,9 +1453,13 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
let wmi = wasmMemoryInterface;
- let e = event_temp_data.event;
+ if (!event_temp.data) {
+ return;
+ }
+
+ let e = event_temp.data.event;
- wmi.storeU32(off(4), event_temp_data.name_code);
+ wmi.storeU32(off(4), event_temp.data.name_code);
if (e.target == document) {
wmi.storeU32(off(4), 1);
} else if (e.target == window) {
@@ -1475,8 +1477,8 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
align(W);
- wmi.storeI32(off(W), event_temp_data.id_ptr);
- wmi.storeUint(off(W), event_temp_data.id_len);
+ wmi.storeI32(off(W), event_temp.data.id_ptr);
+ wmi.storeUint(off(W), event_temp.data.id_len);
align(8);
wmi.storeF64(off(8), e.timeStamp*1e-3);
@@ -1518,7 +1520,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
} else if (e instanceof KeyboardEvent) {
// Note: those strings are constructed
// on the native side from buffers that
- // are filled later, so skip them
+ // are filled later, so skip them
const keyPtr = off(W*2, W);
const codePtr = off(W*2, W);
@@ -1531,15 +1533,49 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
wmi.storeU8(off(1), !!e.repeat);
- wmi.storeI32(off(W), e.key.length)
- wmi.storeI32(off(W), e.code.length)
+ wmi.storeInt(off(W, W), e.key.length)
+ wmi.storeInt(off(W, W), e.code.length)
wmi.storeString(off(16, 1), e.key);
wmi.storeString(off(16, 1), e.code);
} else if (e.type === 'scroll') {
- wmi.storeF64(off(8), window.scrollX);
- wmi.storeF64(off(8), window.scrollY);
+ wmi.storeF64(off(8, 8), window.scrollX);
+ wmi.storeF64(off(8, 8), window.scrollY);
} else if (e.type === 'visibilitychange') {
wmi.storeU8(off(1), !document.hidden);
+ } else if (e instanceof GamepadEvent) {
+ const idPtr = off(W*2, W);
+ const mappingPtr = off(W*2, W);
+
+ wmi.storeI32(off(W, W), e.gamepad.index);
+ wmi.storeU8(off(1), !!e.gamepad.connected);
+ wmi.storeF64(off(8, 8), e.gamepad.timestamp);
+
+ wmi.storeInt(off(W, W), e.gamepad.buttons.length);
+ wmi.storeInt(off(W, W), e.gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < e.gamepad.buttons.length) {
+ let b = e.gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < e.gamepad.axes.length) {
+ let a = e.gamepad.axes[i];
+ wmi.storeF64(off(8, 8), a);
+ } else {
+ off(8, 8);
+ }
+ }
+
+ wmi.storeInt(off(W, W), e.gamepad.id.length)
+ wmi.storeInt(off(W, W), e.gamepad.mapping.length)
+ wmi.storeString(off(64, 1), e.gamepad.id);
+ wmi.storeString(off(64, 1), e.gamepad.mapping);
}
},
@@ -1552,12 +1588,30 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
}
let listener = (e) => {
- const odin_ctx = wasmMemoryInterface.exports.default_context_ptr();
- event_temp_data.id_ptr = id_ptr;
- event_temp_data.id_len = id_len;
- event_temp_data.event = e;
- event_temp_data.name_code = name_code;
- wasmMemoryInterface.exports.odin_dom_do_event_callback(data, callback, odin_ctx);
+ let event_data = {};
+ event_data.id_ptr = id_ptr;
+ event_data.id_len = id_len;
+ event_data.event = e;
+ event_data.name_code = name_code;
+
+ eventQueue.push({event_data: event_data, data: data, callback: callback});
+ };
+ wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
+ element.addEventListener(name, listener, !!use_capture);
+ return true;
+ },
+
+ add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+ let element = window;
+ let listener = (e) => {
+ let event_data = {};
+ event_data.id_ptr = 0;
+ event_data.id_len = 0;
+ event_data.event = e;
+ event_data.name_code = name_code;
+
+ eventQueue.push({event_data: event_data, data: data, callback: callback});
};
wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
element.addEventListener(name, listener, !!use_capture);
@@ -1579,24 +1633,6 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
element.removeEventListener(name, listener);
return true;
},
-
-
- add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
- let name = wasmMemoryInterface.loadString(name_ptr, name_len);
- let element = window;
- let listener = (e) => {
- const odin_ctx = wasmMemoryInterface.exports.default_context_ptr();
- event_temp_data.id_ptr = 0;
- event_temp_data.id_len = 0;
- event_temp_data.event = e;
- event_temp_data.name_code = name_code;
- wasmMemoryInterface.exports.odin_dom_do_event_callback(data, callback, odin_ctx);
- };
- wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
- element.addEventListener(name, listener, !!use_capture);
- return true;
- },
-
remove_window_event_listener: (name_ptr, name_len, data, callback) => {
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = window;
@@ -1612,18 +1648,18 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
},
event_stop_propagation: () => {
- if (event_temp_data && event_temp_data.event) {
- event_temp_data.event.stopPropagation();
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.stopPropagation();
}
},
event_stop_immediate_propagation: () => {
- if (event_temp_data && event_temp_data.event) {
- event_temp_data.event.stopImmediatePropagation();
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.stopImmediatePropagation();
}
},
event_prevent_default: () => {
- if (event_temp_data && event_temp_data.event) {
- event_temp_data.event.preventDefault();
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.preventDefault();
}
},
@@ -1644,6 +1680,76 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
return false;
},
+ get_gamepad_state: (gamepad_id, ep) => {
+ let index = gamepad_id;
+ let gps = navigator.getGamepads();
+ if (0 <= index && index < gps.length) {
+ let gamepad = gps[index];
+ if (!gamepad) {
+ return false;
+ }
+
+ const W = wasmMemoryInterface.intSize;
+ let offset = ep;
+ let off = (amount, alignment) => {
+ if (alignment === undefined) {
+ alignment = Math.min(amount, W);
+ }
+ if (offset % alignment != 0) {
+ offset += alignment - (offset%alignment);
+ }
+ let x = offset;
+ offset += amount;
+ return x;
+ };
+
+ let align = (alignment) => {
+ const modulo = offset & (alignment-1);
+ if (modulo != 0) {
+ offset += alignment - modulo
+ }
+ };
+
+ let wmi = wasmMemoryInterface;
+
+ const idPtr = off(W*2, W);
+ const mappingPtr = off(W*2, W);
+
+ wmi.storeI32(off(W), gamepad.index);
+ wmi.storeU8(off(1), !!gamepad.connected);
+ wmi.storeF64(off(8), gamepad.timestamp);
+
+ wmi.storeInt(off(W), gamepad.buttons.length);
+ wmi.storeInt(off(W), gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < gamepad.buttons.length) {
+ let b = gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < gamepad.axes.length) {
+ wmi.storeF64(off(8, 8), gamepad.axes[i]);
+ } else {
+ off(8, 8);
+ }
+ }
+
+ wmi.storeInt(off(W, W), gamepad.id.length)
+ wmi.storeInt(off(W, W), gamepad.mapping.length)
+ wmi.storeString(off(64, 1), gamepad.id);
+ wmi.storeString(off(64, 1), gamepad.mapping);
+
+ return true;
+ }
+ return false;
+ },
+
get_element_value_f64: (id_ptr, id_len) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
let element = getElement(id);
@@ -1696,6 +1802,55 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
}
},
+ get_element_key_f64: (id_ptr, id_len, key_ptr, key_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ return element ? element[key] : 0;
+ },
+ get_element_key_string: (id_ptr, id_len, key_ptr, key_len, buf_ptr, buf_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element) {
+ let str = element[key];
+ if (buf_len > 0 && buf_ptr) {
+ let n = Math.min(buf_len, str.length);
+ str = str.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str))
+ return n;
+ }
+ }
+ return 0;
+ },
+ get_element_key_string_length: (id_ptr, id_len, key_ptr, key_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element && element[key]) {
+ return element[key].length;
+ }
+ return 0;
+ },
+
+ set_element_key_f64: (id_ptr, id_len, key_ptr, key_len, value) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element) {
+ element[key] = value;
+ }
+ },
+ set_element_key_string: (id_ptr, id_len, key_ptr, key_len, value_ptr, value_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
+ let element = getElement(id);
+ if (element) {
+ element[key] = value;
+ }
+ },
+
get_bounding_client_rect: (rect_ptr, id_ptr, id_len) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
@@ -1750,7 +1905,10 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemory
}
wasmMemoryInterface.setIntSize(intSize);
- let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory);
+ let eventQueue = new Array();
+ let event_temp = {};
+
+ let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory, eventQueue, event_temp);
let exports = {};
if (extraForeignImports !== undefined) {
@@ -1775,14 +1933,14 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemory
exports._start();
- // Define a `@export step :: proc(dt: f32) -> (keep_going: bool) {`
+ // Define a `@export step :: proc(current_type: f64) -> (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) {
const odin_ctx = exports.default_context_ptr();
let prevTimeStamp = undefined;
- const step = (currTimeStamp) => {
+ function step(currTimeStamp) {
if (prevTimeStamp == undefined) {
prevTimeStamp = currTimeStamp;
}
@@ -1790,13 +1948,20 @@ async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemory
const dt = (currTimeStamp - prevTimeStamp)*0.001;
prevTimeStamp = currTimeStamp;
- if (!exports.step(dt, odin_ctx)) {
+ while (eventQueue.length > 0) {
+ let e = eventQueue.shift()
+ event_temp.data = e.event_data;
+ exports.odin_dom_do_event_callback(e.data, e.callback, odin_ctx);
+ }
+ event_temp.data = null;
+
+ if (!exports.step(currTimeStamp*0.001, odin_ctx)) {
exports._end();
return;
}
window.requestAnimationFrame(step);
- };
+ }
window.requestAnimationFrame(step);
} else {
diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin
index 38d95e754..8d50f1690 100644
--- a/core/sys/wasm/wasi/wasi_api.odin
+++ b/core/sys/wasm/wasi/wasi_api.odin
@@ -1,4 +1,4 @@
-//+build wasm32
+#+build wasm32
package sys_wasi
foreign import wasi "wasi_snapshot_preview1"
diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin
index 1e34f1fd6..f834511d4 100644
--- a/core/sys/windows/advapi32.odin
+++ b/core/sys/windows/advapi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import advapi32 "system:Advapi32.lib"
diff --git a/core/sys/windows/bcrypt.odin b/core/sys/windows/bcrypt.odin
index d891aa92b..f15f1e305 100644
--- a/core/sys/windows/bcrypt.odin
+++ b/core/sys/windows/bcrypt.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import bcrypt "system:Bcrypt.lib"
diff --git a/core/sys/windows/bluetooth.odin b/core/sys/windows/bluetooth.odin
index 7bfb7ea96..86c66b9a1 100644
--- a/core/sys/windows/bluetooth.odin
+++ b/core/sys/windows/bluetooth.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:bthprops.lib"
diff --git a/core/sys/windows/codepage.odin b/core/sys/windows/codepage.odin
index 90040f1ee..527289f03 100644
--- a/core/sys/windows/codepage.odin
+++ b/core/sys/windows/codepage.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin
index 9c4404a9d..477800413 100644
--- a/core/sys/windows/comctl32.odin
+++ b/core/sys/windows/comctl32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Comctl32.lib"
diff --git a/core/sys/windows/comdlg32.odin b/core/sys/windows/comdlg32.odin
index 30d9b169c..a9800b47a 100644
--- a/core/sys/windows/comdlg32.odin
+++ b/core/sys/windows/comdlg32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Comdlg32.lib"
diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin
index cb5458248..336992b4a 100644
--- a/core/sys/windows/dbghelp.odin
+++ b/core/sys/windows/dbghelp.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Dbghelp.lib"
diff --git a/core/sys/windows/dnsapi.odin b/core/sys/windows/dnsapi.odin
index dd2d1acee..4fd9f7a19 100644
--- a/core/sys/windows/dnsapi.odin
+++ b/core/sys/windows/dnsapi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Dnsapi.lib"
diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin
index 91911baae..11a46f53a 100644
--- a/core/sys/windows/dwmapi.odin
+++ b/core/sys/windows/dwmapi.odin
@@ -1,10 +1,10 @@
-// +build windows
+#+build windows
package sys_windows
foreign import dwmapi "system:Dwmapi.lib"
DWMWINDOWATTRIBUTE :: enum {
- DWMWA_NCRENDERING_ENABLED,
+ DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
@@ -28,7 +28,7 @@ DWMWINDOWATTRIBUTE :: enum {
DWMWA_TEXT_COLOR,
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
DWMWA_SYSTEMBACKDROP_TYPE,
- DWMWA_LAST,
+ DWMWA_LAST,
}
DWMNCRENDERINGPOLICY :: enum {
diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin
index 5cbafddba..1d7a93d85 100644
--- a/core/sys/windows/gdi32.odin
+++ b/core/sys/windows/gdi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:math/fixed"
diff --git a/core/sys/windows/hidpi.odin b/core/sys/windows/hidpi.odin
index bea03694e..5e9787527 100644
--- a/core/sys/windows/hidpi.odin
+++ b/core/sys/windows/hidpi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:c"
diff --git a/core/sys/windows/hidusage.odin b/core/sys/windows/hidusage.odin
index a32aa7b9f..eb2a85f2e 100644
--- a/core/sys/windows/hidusage.odin
+++ b/core/sys/windows/hidusage.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
USAGE :: distinct USHORT
diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin
index 4c2534c10..7a6e545ac 100644
--- a/core/sys/windows/ip_helper.odin
+++ b/core/sys/windows/ip_helper.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:iphlpapi.lib"
diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin
index 54dc11389..2771581e6 100644
--- a/core/sys/windows/kernel32.odin
+++ b/core/sys/windows/kernel32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
@@ -400,6 +400,9 @@ foreign kernel32 {
GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID ---
GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
GlobalFree :: proc(mem: LPVOID) -> LPVOID ---
+
+ GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID ---
+ GlobalUnlock :: proc(hMem: HGLOBAL) -> BOOL ---
ReadDirectoryChangesW :: proc(
hDirectory: HANDLE,
@@ -1175,17 +1178,17 @@ SYSTEM_POWER_STATUS :: struct {
}
AC_Line_Status :: enum BYTE {
- Offline = 0,
- Online = 1,
- Unknown = 255,
+ Offline = 0,
+ Online = 1,
+ Unknown = 255,
}
Battery_Flag :: enum BYTE {
- High = 0,
- Low = 1,
- Critical = 2,
- Charging = 3,
- No_Battery = 7,
+ High = 0,
+ Low = 1,
+ Critical = 2,
+ Charging = 3,
+ No_Battery = 7,
}
Battery_Flags :: bit_set[Battery_Flag; BYTE]
diff --git a/core/sys/windows/key_codes.odin b/core/sys/windows/key_codes.odin
index 284b0e437..0991ca4b3 100644
--- a/core/sys/windows/key_codes.odin
+++ b/core/sys/windows/key_codes.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://docs.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input
diff --git a/core/sys/windows/known_folders.odin b/core/sys/windows/known_folders.odin
index 439d65faf..cbaf5eeeb 100644
--- a/core/sys/windows/known_folders.odin
+++ b/core/sys/windows/known_folders.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
FOLDERID_NetworkFolder :: GUID {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}}
diff --git a/core/sys/windows/netapi32.odin b/core/sys/windows/netapi32.odin
index d9f75c623..9442193ca 100644
--- a/core/sys/windows/netapi32.odin
+++ b/core/sys/windows/netapi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import netapi32 "system:Netapi32.lib"
diff --git a/core/sys/windows/ntdll.odin b/core/sys/windows/ntdll.odin
index 23444ff34..747130749 100644
--- a/core/sys/windows/ntdll.odin
+++ b/core/sys/windows/ntdll.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import ntdll_lib "system:ntdll.lib"
diff --git a/core/sys/windows/shcore.odin b/core/sys/windows/shcore.odin
index 54f67989e..08a76ebe6 100644
--- a/core/sys/windows/shcore.odin
+++ b/core/sys/windows/shcore.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin
index 7340ae4d4..54cee718c 100644
--- a/core/sys/windows/shell32.odin
+++ b/core/sys/windows/shell32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import shell32 "system:Shell32.lib"
diff --git a/core/sys/windows/shlwapi.odin b/core/sys/windows/shlwapi.odin
index bf9d2d1e8..095fff304 100644
--- a/core/sys/windows/shlwapi.odin
+++ b/core/sys/windows/shlwapi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import shlwapi "system:shlwapi.lib"
diff --git a/core/sys/windows/synchronization.odin b/core/sys/windows/synchronization.odin
index 79efaab34..bcaeb3f5f 100644
--- a/core/sys/windows/synchronization.odin
+++ b/core/sys/windows/synchronization.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import Synchronization "system:Synchronization.lib"
diff --git a/core/sys/windows/system_params.odin b/core/sys/windows/system_params.odin
index e94d777bf..e463feb7e 100644
--- a/core/sys/windows/system_params.odin
+++ b/core/sys/windows/system_params.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// Parameter for SystemParametersInfo.
diff --git a/core/sys/windows/tlhelp.odin b/core/sys/windows/tlhelp.odin
index 45d5a3ff9..006c9c330 100644
--- a/core/sys/windows/tlhelp.odin
+++ b/core/sys/windows/tlhelp.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin
index d9a6bd1fd..934d103e5 100644
--- a/core/sys/windows/types.odin
+++ b/core/sys/windows/types.odin
@@ -3546,11 +3546,11 @@ SIGDN :: enum c_int {
}
SIATTRIBFLAGS :: enum c_int {
- AND = 0x1,
- OR = 0x2,
- APPCOMPAT = 0x3,
- MASK = 0x3,
- ALLITEMS = 0x4000,
+ AND = 0x1,
+ OR = 0x2,
+ APPCOMPAT = 0x3,
+ MASK = 0x3,
+ ALLITEMS = 0x4000,
}
FDAP :: enum c_int {
@@ -4503,35 +4503,35 @@ DNS_INFO_NO_RECORDS :: 9501
DNS_QUERY_NO_RECURSION :: 0x00000004
DNS_RECORD :: struct { // aka DNS_RECORDA
- pNext: ^DNS_RECORD,
- pName: cstring,
- wType: WORD,
- wDataLength: USHORT,
- Flags: DWORD,
- dwTtl: DWORD,
- _: DWORD,
- Data: struct #raw_union {
- CNAME: DNS_PTR_DATAA,
- A: u32be, // Ipv4 Address
- AAAA: u128be, // Ipv6 Address
- TXT: DNS_TXT_DATAA,
- NS: DNS_PTR_DATAA,
- MX: DNS_MX_DATAA,
- SRV: DNS_SRV_DATAA,
- },
+ pNext: ^DNS_RECORD,
+ pName: cstring,
+ wType: WORD,
+ wDataLength: USHORT,
+ Flags: DWORD,
+ dwTtl: DWORD,
+ _: DWORD,
+ Data: struct #raw_union {
+ CNAME: DNS_PTR_DATAA,
+ A: u32be, // Ipv4 Address
+ AAAA: u128be, // Ipv6 Address
+ TXT: DNS_TXT_DATAA,
+ NS: DNS_PTR_DATAA,
+ MX: DNS_MX_DATAA,
+ SRV: DNS_SRV_DATAA,
+ },
}
DNS_TXT_DATAA :: struct {
- dwStringCount: DWORD,
- pStringArray: cstring,
+ dwStringCount: DWORD,
+ pStringArray: cstring,
}
DNS_PTR_DATAA :: cstring
DNS_MX_DATAA :: struct {
- pNameExchange: cstring, // the hostname
- wPreference: WORD, // lower values preferred
- _: WORD, // padding.
+ pNameExchange: cstring, // the hostname
+ wPreference: WORD, // lower values preferred
+ _: WORD, // padding.
}
DNS_SRV_DATAA :: struct {
pNameTarget: cstring,
diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin
index f1232c680..514592e7b 100644
--- a/core/sys/windows/user32.odin
+++ b/core/sys/windows/user32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "base:intrinsics"
@@ -66,7 +66,7 @@ foreign user32 {
RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE ---
EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT ---
EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT ---
- GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL ---
+ GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> INT ---
TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL ---
DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
@@ -142,7 +142,7 @@ foreign user32 {
AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL ---
GetMenu :: proc(hWnd: HWND) -> HMENU ---
SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL ---
- TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> BOOL ---
+ TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> INT ---
RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT ---
CreateAcceleratorTableW :: proc(paccel: LPACCEL, cAccel: INT) -> HACCEL ---
@@ -305,6 +305,13 @@ foreign user32 {
GetProcessWindowStation :: proc() -> HWINSTA ---
GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL ---
+
+ OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL ---
+ CloseClipboard :: proc() -> BOOL ---
+ GetClipboardData :: proc(uFormat: UINT) -> HANDLE ---
+ SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE ---
+ IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL ---
+ EmptyClipboard :: proc() -> BOOL ---
}
CreateWindowW :: #force_inline proc "system" (
@@ -746,3 +753,31 @@ WinEventFlag :: enum DWORD {
SKIPOWNPROCESS = 1,
INCONTEXT = 2,
}
+
+// Standard Clipboard Formats
+CF_TEXT :: 1
+CF_BITMAP :: 2
+CF_METAFILEPICT :: 3
+CF_SYLK :: 4
+CF_DIF :: 5
+CF_TIFF :: 6
+CF_OEMTEXT :: 7
+CF_DIB :: 8
+CF_PALETTE :: 9
+CF_PENDATA :: 10
+CF_RIFF :: 11
+CF_WAVE :: 12
+CF_UNICODETEXT :: 13
+CF_ENHMETAFILE :: 14
+CF_HDROP :: 15
+CF_LOCALE :: 16
+CF_DIBV5 :: 17
+CF_DSPBITMAP :: 0x0082
+CF_DSPENHMETAFILE :: 0x008E
+CF_DSPMETAFILEPICT :: 0x0083
+CF_DSPTEXT :: 0x0081
+CF_GDIOBJFIRST :: 0x0300
+CF_GDIOBJLAST :: 0x03FF
+CF_OWNERDISPLAY :: 0x0080
+CF_PRIVATEFIRST :: 0x0200
+CF_PRIVATELAST :: 0x02FF
diff --git a/core/sys/windows/userenv.odin b/core/sys/windows/userenv.odin
index a31e363e1..2a2209d2c 100644
--- a/core/sys/windows/userenv.odin
+++ b/core/sys/windows/userenv.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import userenv "system:Userenv.lib"
diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin
index 929df1765..b3eb800bc 100644
--- a/core/sys/windows/util.odin
+++ b/core/sys/windows/util.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "base:runtime"
diff --git a/core/sys/windows/ux_theme.odin b/core/sys/windows/ux_theme.odin
index 7af399361..527abd62f 100644
--- a/core/sys/windows/ux_theme.odin
+++ b/core/sys/windows/ux_theme.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import uxtheme "system:UxTheme.lib"
diff --git a/core/sys/windows/wgl.odin b/core/sys/windows/wgl.odin
index d0d96d90b..8fea55c3d 100644
--- a/core/sys/windows/wgl.odin
+++ b/core/sys/windows/wgl.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:c"
diff --git a/core/sys/windows/wglext.odin b/core/sys/windows/wglext.odin
index 0c4b51d65..4c76b39ec 100644
--- a/core/sys/windows/wglext.odin
+++ b/core/sys/windows/wglext.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// WGL_ARB_buffer_region
diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin
index 888c5ccf9..d69771bdf 100644
--- a/core/sys/windows/window_messages.odin
+++ b/core/sys/windows/window_messages.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
WM_NULL :: 0x0000
diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin
index 8882dad71..b3b470619 100644
--- a/core/sys/windows/winerror.odin
+++ b/core/sys/windows/winerror.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://learn.microsoft.com/en-us/windows/win32/api/winerror/
@@ -213,6 +213,7 @@ ERROR_BROKEN_PIPE : DWORD : 109
ERROR_CALL_NOT_IMPLEMENTED : DWORD : 120
ERROR_INSUFFICIENT_BUFFER : DWORD : 122
ERROR_INVALID_NAME : DWORD : 123
+ERROR_NEGATIVE_SEEK : DWORD : 131
ERROR_BAD_ARGUMENTS : DWORD : 160
ERROR_LOCK_FAILED : DWORD : 167
ERROR_ALREADY_EXISTS : DWORD : 183
diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin
index a1786c27a..3c7ec80e7 100644
--- a/core/sys/windows/winmm.odin
+++ b/core/sys/windows/winmm.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import winmm "system:Winmm.lib"
diff --git a/core/sys/windows/winnls.odin b/core/sys/windows/winnls.odin
index 292d2fad2..ffb2638d5 100644
--- a/core/sys/windows/winnls.odin
+++ b/core/sys/windows/winnls.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
LCTYPE :: distinct DWORD
diff --git a/core/sys/windows/winver.odin b/core/sys/windows/winver.odin
index 091d53d3a..47751dab7 100644
--- a/core/sys/windows/winver.odin
+++ b/core/sys/windows/winver.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import version "system:version.lib"
diff --git a/core/sys/windows/wow64_apiset.odin b/core/sys/windows/wow64_apiset.odin
index 28558e9ca..3d29b786e 100644
--- a/core/sys/windows/wow64_apiset.odin
+++ b/core/sys/windows/wow64_apiset.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin
index e9bf8abc9..5b2952495 100644
--- a/core/sys/windows/ws2_32.odin
+++ b/core/sys/windows/ws2_32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// Define flags to be used with the WSAAsyncSelect() call.
diff --git a/core/testing/events.odin b/core/testing/events.odin
index c9c4b0271..1a47e2d68 100644
--- a/core/testing/events.odin
+++ b/core/testing/events.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package testing
/*
diff --git a/core/testing/logging.odin b/core/testing/logging.odin
index 1c3fc4603..041489dab 100644
--- a/core/testing/logging.odin
+++ b/core/testing/logging.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package testing
/*
diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin
index 81f1d0646..6752cd79b 100644
--- a/core/testing/reporting.odin
+++ b/core/testing/reporting.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package testing
/*
diff --git a/core/testing/runner.odin b/core/testing/runner.odin
index 386ba8cb5..6b9d610ed 100644
--- a/core/testing/runner.odin
+++ b/core/testing/runner.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package testing
/*
@@ -204,6 +204,10 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
}
}
+ when ODIN_OS == .Windows {
+ console_ansi_init()
+ }
+
stdout := io.to_writer(os.stream_from_handle(os.stdout))
stderr := io.to_writer(os.stream_from_handle(os.stderr))
diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin
new file mode 100644
index 000000000..401804c71
--- /dev/null
+++ b/core/testing/runner_windows.odin
@@ -0,0 +1,22 @@
+#+private
+package testing
+
+import win32 "core:sys/windows"
+
+console_ansi_init :: proc() {
+ stdout := win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)
+ if stdout != win32.INVALID_HANDLE && stdout != nil {
+ old_console_mode: u32
+ if win32.GetConsoleMode(stdout, &old_console_mode) {
+ win32.SetConsoleMode(stdout, old_console_mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ }
+ }
+
+ stderr := win32.GetStdHandle(win32.STD_ERROR_HANDLE)
+ if stderr != win32.INVALID_HANDLE && stderr != nil {
+ old_console_mode: u32
+ if win32.GetConsoleMode(stderr, &old_console_mode) {
+ win32.SetConsoleMode(stderr, old_console_mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ }
+ }
+}
diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin
index 047ea0b3a..2f1f7c89a 100644
--- a/core/testing/signal_handler.odin
+++ b/core/testing/signal_handler.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package testing
/*
diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin
index 27d1a0735..7442c100c 100644
--- a/core/testing/signal_handler_libc.odin
+++ b/core/testing/signal_handler_libc.odin
@@ -1,5 +1,5 @@
-//+private
-//+build windows, linux, darwin, freebsd, openbsd, netbsd, haiku
+#+private
+#+build windows, linux, darwin, freebsd, openbsd, netbsd, haiku
package testing
/*
@@ -26,6 +26,8 @@ import "core:os"
@(private="file", thread_local)
local_test_index: libc.sig_atomic_t
+@(private="file", thread_local)
+local_test_index_set: bool
// 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
@@ -45,6 +47,13 @@ stop_runner_callback :: proc "c" (sig: libc.int) {
@(private="file")
stop_test_callback :: proc "c" (sig: libc.int) {
+ if !local_test_index_set {
+ // We're a thread created by a test thread.
+ //
+ // There's nothing we can do to inform the test runner about who
+ // signalled, so hopefully the test will handle their own sub-threads.
+ return
+ }
if local_test_index == -1 {
// We're the test runner, and we ourselves have caught a signal from
// which there is no recovery.
@@ -114,6 +123,7 @@ This is a dire bug and should be reported to the Odin developers.
_setup_signal_handler :: proc() {
local_test_index = -1
+ local_test_index_set = true
// Catch user interrupt / CTRL-C.
libc.signal(libc.SIGINT, stop_runner_callback)
@@ -135,6 +145,7 @@ _setup_signal_handler :: proc() {
_setup_task_signal_handler :: proc(test_index: int) {
local_test_index = cast(libc.sig_atomic_t)test_index
+ local_test_index_set = true
}
_should_stop_runner :: proc() -> bool {
diff --git a/core/testing/signal_handler_other.odin b/core/testing/signal_handler_other.odin
index 6f39205c7..81f575495 100644
--- a/core/testing/signal_handler_other.odin
+++ b/core/testing/signal_handler_other.odin
@@ -1,5 +1,11 @@
-//+private
-//+build !windows !linux !darwin !freebsd !openbsd !netbsd !haiku
+#+private
+#+build !windows
+#+build !linux
+#+build !darwin
+#+build !freebsd
+#+build !openbsd
+#+build !netbsd
+#+build !haiku
package testing
/*
diff --git a/core/testing/testing.odin b/core/testing/testing.odin
index d5e7c6830..09bf6dc0e 100644
--- a/core/testing/testing.odin
+++ b/core/testing/testing.odin
@@ -105,9 +105,13 @@ cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {
append(&t.cleanups, Internal_Cleanup{procedure, user_data, context})
}
-expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool {
+expect :: proc(t: ^T, ok: bool, msg := "", expr := #caller_expression(ok), loc := #caller_location) -> bool {
if !ok {
- log.error(msg, location=loc)
+ if msg == "" {
+ log.errorf("expected %v to be true", expr, location=loc)
+ } else {
+ log.error(msg, location=loc)
+ }
}
return ok
}
@@ -119,10 +123,10 @@ expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_loc
return ok
}
-expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
+expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location, value_expr := #caller_expression(value)) -> bool where intrinsics.type_is_comparable(T) {
ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected)
if !ok {
- log.errorf("expected %v, got %v", expected, value, location=loc)
+ log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc)
}
return ok
}
diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin
index 521a658e1..49adad4d9 100644
--- a/core/text/edit/text_edit.odin
+++ b/core/text/edit/text_edit.odin
@@ -1,10 +1,9 @@
-package text_edit
-
/*
- Based off the articles by rxi:
- * https://rxi.github.io/textbox_behaviour.html
- * https://rxi.github.io/a_simple_undo_system.html
+Based off the articles by rxi:
+- [[ https://rxi.github.io/textbox_behaviour.html ]]
+- [[ https://rxi.github.io/a_simple_undo_system.html ]]
*/
+package text_edit
import "base:runtime"
import "core:time"
diff --git a/core/text/table/doc.odin b/core/text/table/doc.odin
index 955ab8d21..63275bbc1 100644
--- a/core/text/table/doc.odin
+++ b/core/text/table/doc.odin
@@ -1,8 +1,8 @@
/*
The package `table` implements plain-text/markdown/HTML/custom rendering of tables.
-**Custom rendering example:**
-
+**Custom rendering.**
+Example:
package main
import "core:io"
@@ -24,13 +24,12 @@ The package `table` implements plain-text/markdown/HTML/custom rendering of tabl
}
}
-This outputs:
-
+Output:
A_LONG_ENUM = 54, // A comment about A_LONG_ENUM
AN_EVEN_LONGER_ENUM = 1, // A comment about AN_EVEN_LONGER_ENUM
-**Plain-text rendering example:**
-
+**Plain-text rendering.**
+Example:
package main
import "core:fmt"
@@ -81,8 +80,7 @@ This outputs:
table.write_markdown_table(stdout, tbl)
}
-This outputs:
-
+Output:
+-----------------------------------------------+
| This is a table caption and it is very long |
+------------------+-----------------+----------+
@@ -93,16 +91,12 @@ This outputs:
| a | bbb | c |
+------------------+-----------------+----------+
-and
-
| AAAAAAAAA | B | C |
|:-----------------|:---------------:|---------:|
| 123 | foo | |
| 000000005 | 6.283185 | |
| a | bbb | c |
-respectively.
-
Additionally, if you want to set the alignment and values in-line while
constructing a table, you can use `aligned_row_of_values` or
@@ -116,8 +110,7 @@ constructing a table, you can use `aligned_row_of_values` or
If you only need to build a table once but display it potentially many times,
it may be more efficient to cache the results of your write into a string.
-Here's an example of how you can do that:
-
+Example:
package main
import "core:fmt"
@@ -191,8 +184,7 @@ This package makes use of the `grapheme_count` procedure from the
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:
-
+Example:
package main
import "core:fmt"
@@ -237,7 +229,7 @@ Here is a full example of how well-supported Unicode is with this package:
scripts(stdout)
}
-This will print out:
+Output:
+----------------------------------------------------------------------------------------------------------------------------+
| Tést Suite |
@@ -271,8 +263,7 @@ 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:
-
+Example:
package main
import "core:fmt"
diff --git a/core/text/table/table.odin b/core/text/table/table.odin
index 27c99b1f1..66a7d442b 100644
--- a/core/text/table/table.odin
+++ b/core/text/table/table.odin
@@ -56,7 +56,7 @@ Decorations :: struct {
// Connecting decorations:
nw, n, ne,
- w, x, e,
+ w, x, e,
sw, s, se: string,
// Straight lines:
diff --git a/core/thread/thread.odin b/core/thread/thread.odin
index 17ba1a0a2..c1cbceb42 100644
--- a/core/thread/thread.odin
+++ b/core/thread/thread.odin
@@ -272,7 +272,7 @@ create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil,
t := create(thread_proc, priority)
t.data = rawptr(fn)
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
start(t)
@@ -307,7 +307,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co
t.user_index = 1
t.user_args[0] = data
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
start(t)
@@ -347,7 +347,7 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex
mem.copy(&t.user_args[0], &data, size_of(T))
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
@@ -394,7 +394,7 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2),
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg2))
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
@@ -443,7 +443,7 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg3))
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
@@ -494,7 +494,7 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4:
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg4))
if self_cleanup {
- t.flags += {.Self_Cleanup}
+ intrinsics.atomic_or(&t.flags, {.Self_Cleanup})
}
t.init_context = init_context
diff --git a/core/thread/thread_other.odin b/core/thread/thread_other.odin
index 34bbfda08..dde2a8e48 100644
--- a/core/thread/thread_other.odin
+++ b/core/thread/thread_other.odin
@@ -1,4 +1,4 @@
-//+build js, wasi, orca
+#+build js, wasi, orca
package thread
import "base:intrinsics"
diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin
index da5e116ff..d9166b450 100644
--- a/core/thread/thread_pool.odin
+++ b/core/thread/thread_pool.odin
@@ -60,6 +60,7 @@ pool_thread_runner :: proc(t: ^Thread) {
if task, ok := pool_pop_waiting(pool); ok {
data.task = task
pool_do_work(pool, task)
+ sync.guard(&pool.mutex)
data.task = {}
}
}
@@ -122,9 +123,10 @@ pool_join :: proc(pool: ^Pool) {
for started_count < len(pool.threads) {
started_count = 0
for t in pool.threads {
- if .Started in t.flags {
+ flags := intrinsics.atomic_load(&t.flags)
+ if .Started in flags {
started_count += 1
- if .Joined not_in t.flags {
+ if .Joined not_in flags {
join(t)
}
}
@@ -175,10 +177,12 @@ pool_stop_task :: proc(pool: ^Pool, user_index: int, exit_code: int = 1) -> bool
intrinsics.atomic_sub(&pool.num_outstanding, 1)
intrinsics.atomic_sub(&pool.num_in_processing, 1)
+ old_thread_user_index := t.user_index
+
destroy(t)
replacement := create(pool_thread_runner)
- replacement.user_index = t.user_index
+ replacement.user_index = old_thread_user_index
replacement.data = data
data.task = {}
pool.threads[i] = replacement
@@ -207,10 +211,12 @@ pool_stop_all_tasks :: proc(pool: ^Pool, exit_code: int = 1) {
intrinsics.atomic_sub(&pool.num_outstanding, 1)
intrinsics.atomic_sub(&pool.num_in_processing, 1)
+ old_thread_user_index := t.user_index
+
destroy(t)
replacement := create(pool_thread_runner)
- replacement.user_index = t.user_index
+ replacement.user_index = old_thread_user_index
replacement.data = data
data.task = {}
pool.threads[i] = replacement
diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin
index f56454bfc..9576a3040 100644
--- a/core/thread/thread_unix.odin
+++ b/core/thread/thread_unix.odin
@@ -1,21 +1,18 @@
-// +build linux, darwin, freebsd, openbsd, netbsd, haiku
-// +private
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+private
package thread
+import "base:runtime"
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.
// Also see core/sys/darwin/mach_darwin.odin/semaphore_t.
Thread_Os_Specific :: struct #align(16) {
unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux.
- cond: sync.Cond,
- mutex: sync.Mutex,
+ start_ok: sync.Sema,
}
//
// Creates a thread which will run the given procedure.
@@ -28,14 +25,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// 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)
-
t.id = sync.current_thread_id()
- for (.Started not_in sync.atomic_load(&t.flags)) {
- // HACK: use a timeout so in the event that the condition is signalled at THIS comment's exact point
- // (after checking flags, before starting the wait) it gets itself out of that deadlock after a ms.
- sync.wait_with_timeout(&t.cond, &t.mutex, time.Millisecond)
+ if .Started not_in sync.atomic_load(&t.flags) {
+ sync.wait(&t.start_ok)
}
if .Joined in sync.atomic_load(&t.flags) {
@@ -55,16 +48,20 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
// variable above. We must perform that waiting BEFORE we select the context!
context = _select_context_for_thread(init_context)
- defer _maybe_destroy_default_temp_allocator(init_context)
+ defer {
+ _maybe_destroy_default_temp_allocator(init_context)
+ runtime.run_thread_local_cleaners()
+ }
t.procedure(t)
}
sync.atomic_or(&t.flags, { .Done })
- sync.unlock(&t.mutex)
-
if .Self_Cleanup in sync.atomic_load(&t.flags) {
+ res := unix.pthread_detach(t.unix_thread)
+ assert_contextless(res == 0)
+
t.unix_thread = {}
// NOTE(ftphikari): It doesn't matter which context 'free' received, right?
context = {}
@@ -125,7 +122,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
_start :: proc(t: ^Thread) {
sync.atomic_or(&t.flags, { .Started })
- sync.signal(&t.cond)
+ sync.post(&t.start_ok)
}
_is_done :: proc(t: ^Thread) -> bool {
@@ -133,24 +130,18 @@ _is_done :: proc(t: ^Thread) -> bool {
}
_join :: proc(t: ^Thread) {
- // sync.guard(&t.mutex)
-
if unix.pthread_equal(unix.pthread_self(), t.unix_thread) {
return
}
- // Preserve other flags besides `.Joined`, like `.Started`.
- unjoined := sync.atomic_load(&t.flags) - {.Joined}
- joined := unjoined + {.Joined}
-
- // Try to set `t.flags` from unjoined to joined. If it returns joined,
- // it means the previous value had that flag set and we can return.
- if res, ok := CAS(&t.flags, unjoined, joined); res == joined && !ok {
+ // If the previous value was already `Joined`, then we can return.
+ if .Joined in sync.atomic_or(&t.flags, {.Joined}) {
return
}
+
// Prevent non-started threads from blocking main thread with initial wait
// condition.
- if .Started not_in unjoined {
+ if .Started not_in sync.atomic_load(&t.flags) {
_start(t)
}
unix.pthread_join(t.unix_thread, nil)
diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin
index 8da75a2d9..cc73a2d6a 100644
--- a/core/thread/thread_windows.odin
+++ b/core/thread/thread_windows.odin
@@ -1,8 +1,9 @@
-//+build windows
-//+private
+#+build windows
+#+private
package thread
import "base:intrinsics"
+import "base:runtime"
import "core:sync"
import win32 "core:sys/windows"
@@ -26,7 +27,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
__windows_thread_entry_proc :: proc "system" (t_: rawptr) -> win32.DWORD {
t := (^Thread)(t_)
- if .Joined in t.flags {
+ if .Joined in sync.atomic_load(&t.flags) {
return 0
}
@@ -39,14 +40,17 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
// to t.procedure().
context = _select_context_for_thread(init_context)
- defer _maybe_destroy_default_temp_allocator(init_context)
+ defer {
+ _maybe_destroy_default_temp_allocator(init_context)
+ runtime.run_thread_local_cleaners()
+ }
t.procedure(t)
}
- intrinsics.atomic_store(&t.flags, t.flags + {.Done})
+ intrinsics.atomic_or(&t.flags, {.Done})
- if .Self_Cleanup in t.flags {
+ if .Self_Cleanup in sync.atomic_load(&t.flags) {
win32.CloseHandle(t.win32_thread)
t.win32_thread = win32.INVALID_HANDLE
// NOTE(ftphikari): It doesn't matter which context 'free' received, right?
diff --git a/core/time/datetime/internal.odin b/core/time/datetime/internal.odin
index e7129548e..3477a47f3 100644
--- a/core/time/datetime/internal.odin
+++ b/core/time/datetime/internal.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package datetime
// Internal helper functions for calendrical conversions
diff --git a/core/time/rfc3339.odin b/core/time/rfc3339.odin
index e4c6565d6..20e8ea0bb 100644
--- a/core/time/rfc3339.odin
+++ b/core/time/rfc3339.odin
@@ -187,4 +187,110 @@ scan_digits :: proc(s: string, sep: string, count: int) -> (res: int, ok: bool)
found_sep |= rune(s[count]) == v
}
return res, found_sep
-} \ No newline at end of file
+}
+
+/*
+Serialize the timestamp as a RFC 3339 string.
+
+The boolean `ok` is false if the `time` is not a valid datetime, or if allocating the result string fails.
+
+**Inputs**:
+- `utc_offset`: offset in minutes wrt UTC (ie. the timezone)
+- `include_nanos`: whether to include nanoseconds in the result.
+*/
+time_to_rfc3339 :: proc(time: Time, utc_offset : int = 0, include_nanos := true, allocator := context.allocator) -> (res: string, ok: bool) {
+ utc_offset := utc_offset
+
+ // convert to datetime
+ datetime := time_to_datetime(time) or_return
+
+ if datetime.year < 0 || datetime.year >= 10_000 { return "", false }
+
+ temp_string := [36]u8{}
+ offset : uint = 0
+
+ print_as_fixed_int :: proc(dst: []u8, offset: ^uint, width: i8, i: i64) {
+ i := i
+ width := width
+ for digit_idx in 0..<width {
+ last_digit := i % 10
+ dst[offset^ + uint(width) - uint(digit_idx)-1] = '0' + u8(last_digit)
+ i = i / 10
+ }
+
+ offset^ += uint(width)
+ }
+
+ print_as_fixed_int(temp_string[:], &offset, 4, datetime.year)
+ temp_string[offset] = '-'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(datetime.month))
+ temp_string[offset] = '-'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(datetime.day))
+ temp_string[offset] = 'T'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(datetime.hour))
+ temp_string[offset] = ':'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(datetime.minute))
+ temp_string[offset] = ':'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(datetime.second))
+
+ // turn 123_450_000 to 12345, 5
+ strip_trailing_zeroes_nanos :: proc(n: i64) -> (res: i64, n_digits: i8) {
+ res = n
+ n_digits = 9
+ for res % 10 == 0 {
+ res = res / 10
+ n_digits -= 1
+ }
+ return
+ }
+
+ // pre-epoch times: turn, say, -400ms to +600ms for display
+ nanos := time._nsec % 1_000_000_000
+ if nanos < 0 {
+ nanos += 1_000_000_000
+ }
+
+ if nanos != 0 && include_nanos {
+ temp_string[offset] = '.'
+ offset += 1
+
+ // remove trailing zeroes
+ nanos_nonzero, n_digits := strip_trailing_zeroes_nanos(nanos)
+ assert(nanos_nonzero != 0)
+
+ // write digits, right-to-left
+ for digit_idx : i8 = n_digits-1; digit_idx >= 0; digit_idx -= 1 {
+ digit := u8(nanos_nonzero % 10)
+ temp_string[offset + uint(digit_idx)] = '0' + u8(digit)
+ nanos_nonzero /= 10
+ }
+ offset += uint(n_digits)
+ }
+
+ if utc_offset == 0 {
+ temp_string[offset] = 'Z'
+ offset += 1
+ } else {
+ temp_string[offset] = utc_offset > 0 ? '+' : '-'
+ offset += 1
+ utc_offset = abs(utc_offset)
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(utc_offset / 60))
+ temp_string[offset] = ':'
+ offset += 1
+ print_as_fixed_int(temp_string[:], &offset, 2, i64(utc_offset % 60))
+ }
+
+ res_as_slice, res_alloc := make_slice([]u8, len=offset, allocator = allocator)
+ if res_alloc != nil {
+ return "", false
+ }
+
+ copy(res_as_slice, temp_string[:offset])
+
+ return string(res_as_slice), true
+}
diff --git a/core/time/time.odin b/core/time/time.odin
index 5903b212d..98639b36a 100644
--- a/core/time/time.odin
+++ b/core/time/time.odin
@@ -955,6 +955,24 @@ Convert datetime components into time.
datetime_to_time :: proc{components_to_time, compound_to_time}
/*
+Convert time into datetime.
+*/
+time_to_datetime :: proc "contextless" (t: Time) -> (dt.DateTime, bool) {
+ unix_epoch := dt.DateTime{{1970, 1, 1}, {0, 0, 0, 0}}
+
+ datetime, err := dt.add(unix_epoch, dt.Delta{ nanos = t._nsec })
+ if err != .None {
+ return {}, false
+ }
+ return datetime, true
+}
+
+/*
+Alias for `time_to_datetime`.
+*/
+time_to_compound :: time_to_datetime
+
+/*
Check if a year is a leap year.
*/
is_leap_year :: proc "contextless" (year: int) -> (leap: bool) {
diff --git a/core/time/time_essence.odin b/core/time/time_essence.odin
index b7bc616d8..89883f0b9 100644
--- a/core/time/time_essence.odin
+++ b/core/time/time_essence.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package time
import "core:sys/es"
diff --git a/core/time/time_js.odin b/core/time/time_js.odin
index c5090df90..9175fbfe9 100644
--- a/core/time/time_js.odin
+++ b/core/time/time_js.odin
@@ -1,5 +1,5 @@
-//+private
-//+build js
+#+private
+#+build js
package time
foreign import "odin_env"
diff --git a/core/time/time_orca.odin b/core/time/time_orca.odin
index b2598fd6e..f529790a5 100644
--- a/core/time/time_orca.odin
+++ b/core/time/time_orca.odin
@@ -1,5 +1,5 @@
-//+private
-//+build orca
+#+private
+#+build orca
package time
import "base:intrinsics"
diff --git a/core/time/time_other.odin b/core/time/time_other.odin
index 164d23f25..d89bcbd42 100644
--- a/core/time/time_other.odin
+++ b/core/time/time_other.odin
@@ -1,14 +1,14 @@
-//+private
-//+build !essence
-//+build !js
-//+build !linux
-//+build !openbsd
-//+build !freebsd
-//+build !netbsd
-//+build !darwin
-//+build !wasi
-//+build !windows
-//+build !orca
+#+private
+#+build !essence
+#+build !js
+#+build !linux
+#+build !openbsd
+#+build !freebsd
+#+build !netbsd
+#+build !darwin
+#+build !wasi
+#+build !windows
+#+build !orca
package time
_IS_SUPPORTED :: false
diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin
index 0d7a43aba..61c4e91d3 100644
--- a/core/time/time_unix.odin
+++ b/core/time/time_unix.odin
@@ -1,5 +1,5 @@
-//+private
-//+build darwin, freebsd, openbsd, netbsd
+#+private
+#+build darwin, freebsd, openbsd, netbsd
package time
import "core:sys/posix"
diff --git a/core/time/time_wasi.odin b/core/time/time_wasi.odin
index 88bebe2e3..c16c40cce 100644
--- a/core/time/time_wasi.odin
+++ b/core/time/time_wasi.odin
@@ -1,5 +1,5 @@
-//+private
-//+build wasi
+#+private
+#+build wasi
package time
import "base:intrinsics"
diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin
index 378b914b0..553ea6d4e 100644
--- a/core/time/time_windows.odin
+++ b/core/time/time_windows.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package time
import win32 "core:sys/windows"
diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin
index 841c0b692..3726cff49 100644
--- a/core/time/tsc_darwin.odin
+++ b/core/time/tsc_darwin.odin
@@ -1,4 +1,4 @@
-//+private
+#+private
package time
import "core:sys/unix"
diff --git a/core/time/tsc_freebsd.odin b/core/time/tsc_freebsd.odin
index f4d6ccc3a..dabcb69cb 100644
--- a/core/time/tsc_freebsd.odin
+++ b/core/time/tsc_freebsd.odin
@@ -1,5 +1,5 @@
-//+private
-//+build freebsd
+#+private
+#+build freebsd
package time
import "core:c"
diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin
index 77a79fe52..a83634414 100644
--- a/core/time/tsc_linux.odin
+++ b/core/time/tsc_linux.odin
@@ -1,5 +1,5 @@
-//+private
-//+build linux
+#+private
+#+build linux
package time
import linux "core:sys/linux"
diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin
index 16baa1adf..020ef94e4 100644
--- a/core/unicode/tools/generate_entity_table.odin
+++ b/core/unicode/tools/generate_entity_table.odin
@@ -161,7 +161,7 @@ generate_encoding_entity_table :: proc() {
Input:
entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML.
- Output:
+ Returns:
"decoded" - The decoded rune if found by name, or -1 otherwise.
"ok" - true if found, false if not.
diff --git a/examples/all/all_experimental.odin b/examples/all/all_experimental.odin
index cd60c269c..1d4eb4bb9 100644
--- a/examples/all/all_experimental.odin
+++ b/examples/all/all_experimental.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package all
import c_tokenizer "core:c/frontend/tokenizer"
diff --git a/examples/all/all_linux.odin b/examples/all/all_linux.odin
index 18bba951c..ca51d6562 100644
--- a/examples/all/all_linux.odin
+++ b/examples/all/all_linux.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package all
import linux "core:sys/linux"
diff --git a/examples/all/all_posix.odin b/examples/all/all_posix.odin
index 819dd6dd3..76fac0b87 100644
--- a/examples/all/all_posix.odin
+++ b/examples/all/all_posix.odin
@@ -1,4 +1,4 @@
-//+build darwin, openbsd, freebsd, netbsd
+#+build darwin, openbsd, freebsd, netbsd
package all
import posix "core:sys/posix"
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin
index d66d1ceb0..4b761f0e2 100644
--- a/examples/demo/demo.odin
+++ b/examples/demo/demo.odin
@@ -1,4 +1,4 @@
-//+vet !using-stmt !using-param
+#+vet !using-stmt !using-param
package main
import "core:fmt"
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index 916d4016a..fa7e156ce 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -155,7 +155,7 @@ gb_internal void report_windows_product_type(DWORD ProductType) {
#endif
gb_internal void odin_cpuid(int leaf, int result[]) {
- #if defined(GB_CPU_ARM)
+ #if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
return;
#elif defined(GB_CPU_X86)
@@ -225,6 +225,12 @@ gb_internal void report_cpu_info() {
gb_printf("ARM\n");
#endif
}
+ #elif defined(GB_CPU_RISCV)
+ #if defined(GB_ARCH_64_BIT)
+ gb_printf("RISCV64\n");
+ #else
+ gb_printf("RISCV32\n");
+ #endif
#else
gb_printf("Unknown\n");
#endif
@@ -913,6 +919,8 @@ gb_internal void report_os_info() {
{"23F79", {23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
{"23G80", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
{"23G93", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
+ {"23H124", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
+ {"24A335", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
};
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 3d56f4202..7aff8e650 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -285,6 +285,7 @@ enum VetFlags : u64 {
VetFlag_Deprecated = 1u<<7,
VetFlag_Cast = 1u<<8,
VetFlag_Tabs = 1u<<9,
+ VetFlag_UnusedProcedures = 1u<<10,
VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports,
@@ -316,6 +317,8 @@ u64 get_vet_flag_from_name(String const &name) {
return VetFlag_Cast;
} else if (name == "tabs") {
return VetFlag_Tabs;
+ } else if (name == "unused-procedures") {
+ return VetFlag_UnusedProcedures;
}
return VetFlag_NONE;
}
@@ -383,6 +386,7 @@ struct BuildContext {
u64 vet_flags;
u32 sanitizer_flags;
+ StringSet vet_packages;
bool has_resource;
String link_flags;
@@ -411,6 +415,7 @@ struct BuildContext {
bool no_dynamic_literals;
bool no_output_files;
bool no_crt;
+ bool no_rpath;
bool no_entry_point;
bool no_thread_local;
bool use_lld;
@@ -430,6 +435,7 @@ struct BuildContext {
bool json_errors;
bool has_ansi_terminal_colours;
+ bool fast_isel;
bool ignore_lazy;
bool ignore_llvm_build;
bool ignore_panic;
@@ -1460,8 +1466,6 @@ 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();
@@ -1525,6 +1529,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
metrics = &target_haiku_amd64;
#elif defined(GB_CPU_ARM)
metrics = &target_linux_arm64;
+ #elif defined(GB_CPU_RISCV)
+ metrics = &target_linux_riscv64;
#else
metrics = &target_linux_amd64;
#endif
@@ -1647,7 +1653,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
// Disallow on wasm
bc->use_separate_modules = false;
- } if(bc->metrics.arch == TargetArch_riscv64) {
+ } if(bc->metrics.arch == TargetArch_riscv64 && bc->cross_compiling) {
bc->link_flags = str_lit("-target riscv64 ");
} else {
// NOTE: for targets other than darwin, we don't specify a `-target` link flag.
@@ -2046,10 +2052,11 @@ gb_internal bool init_build_paths(String init_filename) {
gbFile output_file_test;
const char* output_file_name = (const char*)output_file.text;
gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name);
- gb_file_close(&output_file_test);
- gb_file_remove(output_file_name);
- if (output_test_err != 0) {
+ if (output_test_err == 0) {
+ gb_file_close(&output_file_test);
+ gb_file_remove(output_file_name);
+ } else {
String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]);
defer (gb_free(ha, output_file.text));
gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file));
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 1c4b88101..8c051cca2 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -1632,6 +1632,22 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
operand->type = t_source_code_location;
operand->mode = Addressing_Value;
+ } else if (name == "caller_expression") {
+ if (ce->args.count > 1) {
+ error(ce->args[0], "'#caller_expression' expects either 0 or 1 arguments, got %td", ce->args.count);
+ }
+ if (ce->args.count > 0) {
+ Ast *arg = ce->args[0];
+ Operand o = {};
+ Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true);
+ if (e == nullptr || (e->flags & EntityFlag_Param) == 0) {
+ error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name");
+ }
+ arg->Ident.entity = e;
+ }
+
+ operand->type = t_string;
+ operand->mode = Addressing_Value;
} else if (name == "exists") {
if (ce->args.count != 1) {
error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count);
@@ -1792,7 +1808,10 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count);
return false;
}
- if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
+
+ // operand->type can be nil if the condition is a procedure, for example: #assert(assert())
+ // So let's check it before we use it, so we get the same error as if we wrote `#exists(assert())
+ if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) {
gbString str = expr_to_string(ce->args[0]);
error(call, "'%s' is not a constant boolean", str);
gb_string_free(str);
@@ -2048,6 +2067,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return ok;
}
+ if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) {
+ if (build_context.metrics.arch == TargetArch_riscv64) {
+ if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) {
+ error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features");
+ }
+ }
+ }
+
switch (id) {
default:
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name));
@@ -4942,16 +4969,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
check_assignment(c, &x, elem, builtin_name);
Type *t = type_deref(operand->type);
- switch (id) {
- case BuiltinProc_atomic_add:
- case BuiltinProc_atomic_sub:
- if (!is_type_numeric(t)) {
+ if (id != BuiltinProc_atomic_exchange) {
+ if (!is_type_integer_like(t)) {
gbString str = type_to_string(t);
- error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str);
+ error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str);
gb_string_free(str);
} else if (is_type_different_to_arch_endianness(t)) {
gbString str = type_to_string(t);
- error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
+ error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
gb_string_free(str);
}
}
@@ -4987,19 +5012,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
}
Type *t = type_deref(operand->type);
- switch (id) {
- case BuiltinProc_atomic_add_explicit:
- case BuiltinProc_atomic_sub_explicit:
- if (!is_type_numeric(t)) {
+ if (id != BuiltinProc_atomic_exchange_explicit) {
+ if (!is_type_integer_like(t)) {
gbString str = type_to_string(t);
- error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str);
+ error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str);
gb_string_free(str);
} else if (is_type_different_to_arch_endianness(t)) {
gbString str = type_to_string(t);
- error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
+ error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str);
gb_string_free(str);
}
- break;
}
operand->type = elem;
@@ -5192,6 +5214,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
return false;
}
+ if (sz >= 64) {
+ if (is_type_unsigned(x.type)) {
+ add_package_dependency(c, "runtime", "umodti3", true);
+ add_package_dependency(c, "runtime", "udivti3", true);
+ } else {
+ add_package_dependency(c, "runtime", "modti3", true);
+ add_package_dependency(c, "runtime", "divti3", true);
+ }
+ }
+
operand->type = x.type;
operand->mode = Addressing_Value;
}
@@ -5665,6 +5697,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
}
break;
+
+ case BuiltinProc_type_has_shared_fields:
+ {
+ Type *u = check_type(c, ce->args[0]);
+ Type *ut = base_type(u);
+ if (ut == nullptr || ut == t_invalid) {
+ error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) {
+ gbString t = type_to_string(ut);
+ error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ Type *v = check_type(c, ce->args[1]);
+ Type *vt = base_type(v);
+ if (vt == nullptr || vt == t_invalid) {
+ error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name));
+ return false;
+ }
+ if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) {
+ gbString t = type_to_string(vt);
+ error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t);
+ gb_string_free(t);
+ return false;
+ }
+
+ bool is_shared = true;
+
+ for (Entity *v_field : vt->Struct.fields) {
+ bool found = false;
+ for (Entity *u_field : ut->Struct.fields) {
+ if (v_field->token.string == u_field->token.string &&
+ are_types_identical(v_field->type, u_field->type)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ is_shared = false;
+ break;
+ }
+ }
+
+ operand->mode = Addressing_Constant;
+ operand->value = exact_value_bool(is_shared);
+ operand->type = t_untyped_bool;
+ break;
+ }
+
case BuiltinProc_type_field_type:
{
Operand op = {};
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index c60084ec3..3b532a727 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -768,6 +768,19 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) {
if (a->result_count != b->result_count) {
return false;
}
+
+ if (a->c_vararg != b->c_vararg) {
+ return false;
+ }
+
+ if (a->variadic != b->variadic) {
+ return false;
+ }
+
+ if (a->variadic && a->variadic_index != b->variadic_index) {
+ return false;
+ }
+
for (isize i = 0; i < a->param_count; i++) {
Type *x = core_type(a->params->Tuple.variables[i]->type);
Type *y = core_type(b->params->Tuple.variables[i]->type);
@@ -779,6 +792,17 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) {
y = core_type(y->BitSet.underlying);
}
+ // Allow a `#c_vararg args: ..any` with `#c_vararg args: ..foo`.
+ if (a->variadic && i == a->variadic_index) {
+ GB_ASSERT(x->kind == Type_Slice);
+ GB_ASSERT(y->kind == Type_Slice);
+ Type *x_elem = core_type(x->Slice.elem);
+ Type *y_elem = core_type(y->Slice.elem);
+ if (is_type_any(x_elem) || is_type_any(y_elem)) {
+ continue;
+ }
+ }
+
if (!signature_parameter_similar_enough(x, y)) {
return false;
}
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 9cdba2710..fc1aa62e6 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1180,11 +1180,15 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
LIT(article),
LIT(context_name));
} else {
+ ERROR_BLOCK();
error(operand->expr,
"Cannot assign '%s', a type, to %.*s%.*s",
op_type_str,
LIT(article),
LIT(context_name));
+ if (type && are_types_identical(type, t_any)) {
+ error_line("\tSuggestion: 'typeid_of(%s)'", expr_str);
+ }
}
break;
default:
@@ -2571,6 +2575,84 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) {
return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
}
+gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) {
+ type = base_type(type);
+ GB_ASSERT(type->kind == Type_BitSet);
+
+ i64 lower = type->BitSet.lower;
+ i64 upper = type->BitSet.upper;
+ Type *elem = type->BitSet.elem;
+ Type *underlying = type->BitSet.underlying;
+ bool is_backed = underlying != nullptr;
+ gb_unused(is_backed);
+
+ BigInt b_lower = {};
+ BigInt b_upper = {};
+ big_int_from_i64(&b_lower, lower);
+ big_int_from_i64(&b_upper, upper);
+
+
+ BigInt one = {};
+ big_int_from_u64(&one, 1);
+
+ BigInt mask = {};
+
+ if (elem == nullptr) {
+ big_int_from_i64(&mask, -1);
+ } else if (is_type_enum(elem)) {
+ Type *e = base_type(elem);
+ GB_ASSERT(e->kind == Type_Enum);
+ gb_unused(e);
+
+ if ((big_int_cmp(&e->Enum.min_value->value_integer, &b_lower) == 0 || is_backed) &&
+ big_int_cmp(&e->Enum.max_value->value_integer, &b_upper) == 0) {
+
+ i64 lower_base = is_backed ? gb_min(0, lower) : lower;
+ BigInt b_lower_base = {};
+ big_int_from_i64(&b_lower_base, lower_base);
+
+ for (Entity *f : e->Enum.fields) {
+ if (f->kind != Entity_Constant) {
+ continue;
+ }
+ if (f->Constant.value.kind != ExactValue_Integer) {
+ continue;
+ }
+
+ BigInt shift_amount = f->Constant.value.value_integer;
+ big_int_sub_eq(&shift_amount, &b_lower_base);
+
+
+ BigInt value = {};
+ big_int_shl(&value, &one, &shift_amount);
+
+ big_int_or(&mask, &mask, &value);
+ }
+
+ } else {
+ // TODO(bill): enum range based");
+ big_int_from_i64(&mask, -1);
+ }
+ } else {
+ i64 lower_base = lower;
+ for (i64 x = lower; x <= upper; x++) {
+ BigInt shift_amount = {};
+ big_int_from_i64(&shift_amount, x - lower_base);
+
+ BigInt value = {};
+ big_int_shl(&value, &one, &shift_amount);
+
+ big_int_or(&mask, &mask, &value);
+ }
+ }
+
+
+ ExactValue res = {};
+ res.kind = ExactValue_Integer;
+ res.value_integer = mask;
+ return res;
+}
+
gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
switch (op.kind) {
case Token_And: { // Pointer address
@@ -2710,6 +2792,10 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
}
o->value = exact_unary_operator_value(op.kind, o->value, precision, is_unsigned);
+ if (op.kind == Token_Xor && is_type_bit_set(type)) {
+ ExactValue mask = exact_bit_set_all_set_mask(type);
+ o->value = exact_binary_operator_value(Token_And, o->value, mask);
+ }
if (is_type_typed(type)) {
if (node != nullptr) {
@@ -3526,10 +3612,11 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
if (are_types_identical(src_bt, dst_bt)) {
return true;
}
- if (is_type_integer(src_t) && is_type_integer(dst_t)) {
+ if ((is_type_integer(src_t) && is_type_integer(dst_t)) ||
+ is_type_integer(src_t) && is_type_bit_set(dst_t)) {
if (types_have_same_internal_endian(src_t, dst_t)) {
ExactValue src_v = exact_value_to_integer(o->value);
- GB_ASSERT(src_v.kind == ExactValue_Integer);
+ GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid);
BigInt v = src_v.value_integer;
BigInt smax = {};
@@ -3782,10 +3869,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
// NOTE(bill): Allow comparisons between types
if (is_ise_expr(be->left)) {
// Evalute the right before the left for an '.X' expression
- check_expr_or_type(c, y, be->right, type_hint);
+ check_expr_or_type(c, y, be->right, nullptr /* ignore type hint */);
check_expr_or_type(c, x, be->left, y->type);
} else {
- check_expr_or_type(c, x, be->left, type_hint);
+ check_expr_or_type(c, x, be->left, nullptr /* ignore type hint */);
check_expr_or_type(c, y, be->right, x->type);
}
bool xt = x->mode == Addressing_Type;
@@ -4516,7 +4603,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
(operand->value.kind == ExactValue_Integer ||
operand->value.kind == ExactValue_Float)) {
operand->mode = Addressing_Value;
- target_type = t_untyped_nil;
+ // target_type = t_untyped_nil;
operand->value = empty_exact_value;
update_untyped_expr_value(c, operand->expr, operand->value);
break;
@@ -4658,7 +4745,8 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open
check_expr_with_type_hint(c, &operand, index_value, type_hint);
if (operand.mode == Addressing_Invalid) {
if (value) *value = 0;
- return false;
+ // NOTE(bill): return true here to propagate the errors better
+ return true;
}
Type *index_type = t_int;
@@ -4879,7 +4967,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
TypeAndValue tav = fv->value->tav;
if (success_) *success_ = true;
if (finish_) *finish_ = false;
- return tav.value;;
+ return tav.value;
}
}
@@ -4954,7 +5042,6 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper
return value;
}
}
-
if (success_) *success_ = true;
return value;
} else if (value.kind == ExactValue_Quaternion) {
@@ -5652,7 +5739,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) {
if (o.type && is_type_no_copy(o.type)) {
Ast *expr = unparen_expr(o.expr);
- if (expr && o.mode != Addressing_Constant) {
+ if (expr && o.mode != Addressing_Constant && o.mode != Addressing_Type) {
if (expr->kind == Ast_CallExpr) {
// Okay
} else {
@@ -6117,22 +6204,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
Entity *vt = pt->params->Tuple.variables[pt->variadic_index];
o.type = vt->type;
-
- // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array
- if (c->decl) {
- bool found = false;
- for (auto &vr : c->decl->variadic_reuses) {
- if (are_types_identical(vt->type, vr.slice_type)) {
- vr.max_count = gb_max(vr.max_count, variadic_operands.count);
- found = true;
- break;
- }
- }
- if (!found) {
- array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count});
- }
- }
-
} else {
dummy_argument_count += 1;
o.type = t_untyped_nil;
@@ -6326,6 +6397,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
}
score += eval_param_and_score(c, o, t, err, true, var_entity, show_error);
}
+
+ if (!vari_expand && variadic_operands.count != 0) {
+ // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array
+ if (c->decl) {
+ bool found = false;
+ for (auto &vr : c->decl->variadic_reuses) {
+ if (are_types_identical(slice, vr.slice_type)) {
+ vr.max_count = gb_max(vr.max_count, variadic_operands.count);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ array_add(&c->decl->variadic_reuses, VariadicReuseData{slice, variadic_operands.count});
+ }
+ }
+ }
}
if (data) {
@@ -7625,7 +7713,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3);
s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string));
- TypeTuple *tuple = get_record_polymorphic_params(e->type);
+ TypeTuple *tuple = get_record_polymorphic_params(bt);
if (tuple != nullptr) for_array(i, tuple->variables) {
Entity *v = tuple->variables[i];
String name = v->token.string;
@@ -7640,8 +7728,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
s = write_type_to_string(s, v->type, false);
}
} else if (v->kind == Entity_Constant) {
- s = gb_string_append_fmt(s, "=");
- s = write_exact_value_to_string(s, v->Constant.value);
+ if (v->Constant.value.kind != ExactValue_Invalid) {
+ s = gb_string_append_fmt(s, "=");
+ s = write_exact_value_to_string(s, v->Constant.value);
+ }
}
}
s = gb_string_append_fmt(s, ")");
@@ -7717,7 +7807,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
name == "load" ||
name == "load_directory" ||
name == "load_hash" ||
- name == "hash"
+ name == "hash" ||
+ name == "caller_expression"
) {
operand->mode = Addressing_Builtin;
operand->builtin_id = BuiltinProc_DIRECTIVE;
@@ -7997,7 +8088,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc);
String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature;
if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) {
+ ERROR_BLOCK();
error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid));
+
+ error_line("\tSuggested Example: @(enable_target_feature=\"%.*s\")\n", LIT(invalid));
}
}
}
@@ -8632,6 +8726,10 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
error(node, "#caller_location may only be used as a default argument parameter");
o->type = t_source_code_location;
o->mode = Addressing_Value;
+ } else if (name == "caller_expression") {
+ error(node, "#caller_expression may only be used as a default argument parameter");
+ o->type = t_string;
+ o->mode = Addressing_Value;
} else {
if (name == "location") {
init_core_source_code_location(c->checker);
@@ -9033,6 +9131,10 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no
}
if (label != nullptr) {
+ if (c->in_defer) {
+ error(label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(name));
+ return Expr_Expr;
+ }
if (label->kind != Ast_Ident) {
error(label, "A branch statement's label name must be an identifier");
return Expr_Expr;
@@ -10055,6 +10157,22 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
is_constant = o->mode == Addressing_Constant;
}
+ if (elem->kind == Ast_BinaryExpr) {
+ switch (elem->BinaryExpr.op.kind) {
+ case Token_Or:
+ {
+ gbString x = expr_to_string(elem->BinaryExpr.left);
+ gbString y = expr_to_string(elem->BinaryExpr.right);
+ gbString e = expr_to_string(elem);
+ error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e);
+ gb_string_free(e);
+ gb_string_free(y);
+ gb_string_free(x);
+ }
+ break;
+ }
+ }
+
check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal"));
if (o->mode == Addressing_Constant) {
i64 lower = t->BitSet.lower;
@@ -10063,7 +10181,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (lower <= v && v <= upper) {
// okay
} else {
- error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper);
+ gbString s = expr_to_string(o->expr);
+ error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper);
+ gb_string_free(s);
continue;
}
}
@@ -10544,7 +10664,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
o->expr = node;
return kind;
} else if (ok && !is_type_matrix(t)) {
- ExactValue value = type_and_value_of_expr(ie->expr).value;
+ TypeAndValue tav = type_and_value_of_expr(ie->expr);
+ ExactValue value = tav.value;
o->mode = Addressing_Constant;
bool success = false;
bool finish = false;
@@ -10821,7 +10942,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
case Token_context:
{
if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) {
- error(node, "'context' is only allowed within procedures %p", c->curr_proc_decl);
+ error(node, "'context' is only allowed within procedures");
return kind;
}
if (unparen_expr(c->assignment_lhs_hint) == node) {
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 12156df01..74a9e8825 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -199,6 +199,9 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit)
}
break;
+ case Ast_DeferStmt:
+ return check_has_break(stmt->DeferStmt.stmt, label, implicit);
+
case Ast_BlockStmt:
return check_has_break_list(stmt->BlockStmt.stmts, label, implicit);
@@ -1638,6 +1641,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
Ast *expr = unparen_expr(rs->expr);
+ Operand rhs_operand = {};
+
bool is_range = false;
bool is_possibly_addressable = true;
isize max_val_count = 2;
@@ -1695,7 +1700,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
}
}
}
- bool is_ptr = type_deref(operand.type);
+ bool is_ptr = is_type_pointer(operand.type);
Type *t = base_type(type_deref(operand.type));
switch (t->kind) {
@@ -1735,6 +1740,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
break;
case Type_EnumeratedArray:
+ is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr;
array_add(&vals, t->EnumeratedArray.elem);
array_add(&vals, t->EnumeratedArray.index);
break;
@@ -1746,16 +1752,19 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
break;
case Type_DynamicArray:
+ is_possibly_addressable = true;
array_add(&vals, t->DynamicArray.elem);
array_add(&vals, t_int);
break;
case Type_Slice:
+ is_possibly_addressable = true;
array_add(&vals, t->Slice.elem);
array_add(&vals, t_int);
break;
case Type_Map:
+ is_possibly_addressable = true;
is_map = true;
array_add(&vals, t->Map.key);
array_add(&vals, t->Map.value);
@@ -1777,6 +1786,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
case Type_Tuple:
{
+ is_possibly_addressable = false;
+
isize count = t->Tuple.variables.count;
if (count < 1) {
ERROR_BLOCK();
@@ -1806,8 +1817,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
array_add(&vals, e->type);
}
- is_possibly_addressable = false;
-
bool do_break = false;
for (isize i = rs->vals.count-1; i >= 0; i--) {
if (rs->vals[i] != nullptr && count < i+2) {
@@ -1827,6 +1836,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
case Type_Struct:
if (t->Struct.soa_kind != StructSoa_None) {
+ if (t->Struct.soa_kind == StructSoa_Fixed) {
+ is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr;
+ } else {
+ is_possibly_addressable = true;
+ }
is_soa = true;
array_add(&vals, t->Struct.soa_elem);
array_add(&vals, t_int);
@@ -1903,7 +1917,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
if (is_possibly_addressable && i == addressable_index) {
entity->flags &= ~EntityFlag_Value;
} else {
- char const *idx_name = is_map ? "key" : is_bit_set ? "element" : "index";
+ char const *idx_name = is_map ? "key" : (is_bit_set || i == 0) ? "element" : "index";
error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str));
}
}
@@ -2706,6 +2720,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
error(bs->label, "A branch statement's label name must be an identifier");
return;
}
+
Ast *ident = bs->label;
String name = ident->Ident.token.string;
Operand o = {};
@@ -2737,6 +2752,10 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags)
break;
}
+
+ if (ctx->in_defer) {
+ error(bs->label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(token.string));
+ }
}
case_end;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 3767f7666..f0e0acb9b 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -1605,6 +1605,25 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
return false;
}
+gb_internal bool is_caller_expression(Ast *expr) {
+ if (expr->kind == Ast_BasicDirective && expr->BasicDirective.name.string == "caller_expression") {
+ return true;
+ }
+
+ Ast *call = unparen_expr(expr);
+ if (call->kind != Ast_CallExpr) {
+ return false;
+ }
+
+ ast_node(ce, CallExpr, call);
+ if (ce->proc->kind != Ast_BasicDirective) {
+ return false;
+ }
+
+ ast_node(bd, BasicDirective, ce->proc);
+ String name = bd->name.string;
+ return name == "caller_expression";
+}
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
ParameterValue param_value = {};
@@ -1626,7 +1645,19 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_
if (in_type) {
check_assignment(ctx, &o, in_type, str_lit("parameter value"));
}
+ } else if (is_caller_expression(expr)) {
+ if (expr->kind != Ast_BasicDirective) {
+ check_builtin_procedure_directive(ctx, &o, expr, t_string);
+ }
+
+ param_value.kind = ParameterValue_Expression;
+ o.type = t_string;
+ o.mode = Addressing_Value;
+ o.expr = expr;
+ if (in_type) {
+ check_assignment(ctx, &o, in_type, str_lit("parameter value"));
+ }
} else {
if (in_type) {
check_expr_with_type_hint(ctx, &o, expr, in_type);
@@ -1858,6 +1889,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
case ParameterValue_Nil:
break;
case ParameterValue_Location:
+ case ParameterValue_Expression:
case ParameterValue_Value:
gbString str = type_to_string(type);
error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str);
diff --git a/src/checker.cpp b/src/checker.cpp
index b24a7afdb..af1e0e675 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -533,18 +533,13 @@ gb_internal u64 check_vet_flags(CheckerContext *c) {
c->curr_proc_decl->proc_lit) {
file = c->curr_proc_decl->proc_lit->file();
}
- if (file && file->vet_flags_set) {
- return file->vet_flags;
- }
- return build_context.vet_flags;
+
+ return ast_file_vet_flags(file);
}
gb_internal u64 check_vet_flags(Ast *node) {
AstFile *file = node->file();
- if (file && file->vet_flags_set) {
- return file->vet_flags;
- }
- return build_context.vet_flags;
+ return ast_file_vet_flags(file);
}
enum VettedEntityKind {
@@ -681,20 +676,45 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
return false;
}
-gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
- bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
- bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
-
+gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) {
+ u64 original_vet_flags = vet_flags;
Array<VettedEntity> vetted_entities = {};
array_init(&vetted_entities, heap_allocator());
+ defer (array_free(&vetted_entities));
rw_mutex_shared_lock(&scope->mutex);
for (auto const &entry : scope->elements) {
Entity *e = entry.value;
if (e == nullptr) continue;
+
+ vet_flags = original_vet_flags;
+ if (per_entity) {
+ vet_flags = ast_file_vet_flags(e->file);
+ }
+
+ bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
+ bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
+ bool vet_unused_procedures = (vet_flags & VetFlag_UnusedProcedures) != 0;
+
VettedEntity ve_unused = {};
VettedEntity ve_shadowed = {};
- bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused);
+ bool is_unused = false;
+ if (vet_unused && check_vet_unused(c, e, &ve_unused)) {
+ is_unused = true;
+ } else if (vet_unused_procedures &&
+ e->kind == Entity_Procedure) {
+ if (e->flags&EntityFlag_Used) {
+ is_unused = false;
+ } else if (e->flags & EntityFlag_Require) {
+ is_unused = false;
+ } else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") {
+ is_unused = false;
+ } else {
+ is_unused = true;
+ ve_unused.kind = VettedEntity_Unused;
+ ve_unused.entity = e;
+ }
+ }
bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed);
if (is_unused && is_shadowed) {
VettedEntity ve_both = ve_shadowed;
@@ -717,13 +737,18 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
}
rw_mutex_shared_unlock(&scope->mutex);
- gb_sort(vetted_entities.data, vetted_entities.count, gb_size_of(VettedEntity), vetted_entity_variable_pos_cmp);
+ array_sort(vetted_entities, vetted_entity_variable_pos_cmp);
for (auto const &ve : vetted_entities) {
Entity *e = ve.entity;
Entity *other = ve.other;
String name = e->token.string;
+ vet_flags = original_vet_flags;
+ if (per_entity) {
+ vet_flags = ast_file_vet_flags(e->file);
+ }
+
if (ve.kind == VettedEntity_Shadowed_And_Unused) {
error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
} else if (vet_flags) {
@@ -732,6 +757,9 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
+ if (e->kind == Entity_Procedure && (vet_flags & VetFlag_UnusedProcedures) != 0) {
+ error(e->token, "'%.*s' declared but not used", LIT(name));
+ }
if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) {
error(e->token, "'%.*s' declared but not used", LIT(name));
}
@@ -749,7 +777,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
}
}
- array_free(&vetted_entities);
+}
+
+
+gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
+ check_scope_usage_internal(c, scope, vet_flags, false);
for (Scope *child = scope->head_child; child != nullptr; child = child->next) {
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
@@ -1786,7 +1818,9 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti
entity->flags |= EntityFlag_Used;
if (entity_has_deferred_procedure(entity)) {
Entity *deferred = entity->Procedure.deferred_procedure.entity;
- add_entity_use(c, nullptr, deferred);
+ if (deferred != entity) {
+ add_entity_use(c, nullptr, deferred);
+ }
}
if (identifier == nullptr || identifier->kind != Ast_Ident) {
return;
@@ -3174,8 +3208,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
return true;
} else if (name == "link_prefix") {
if (ev.kind == ExactValue_String) {
- String link_prefix = ev.value_string;
- if (!is_foreign_name_valid(link_prefix)) {
+ String link_prefix = string_trim_whitespace(ev.value_string);
+ if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) {
error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix));
} else {
c->foreign_context.link_prefix = link_prefix;
@@ -3186,8 +3220,8 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
return true;
} else if (name == "link_suffix") {
if (ev.kind == ExactValue_String) {
- String link_suffix = ev.value_string;
- if (!is_foreign_name_valid(link_suffix)) {
+ String link_suffix = string_trim_whitespace(ev.value_string);
+ if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) {
error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix));
} else {
c->foreign_context.link_suffix = link_suffix;
@@ -3489,7 +3523,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string;
- if (!is_foreign_name_valid(ac->link_prefix)) {
+ if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) {
error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
}
} else {
@@ -3501,7 +3535,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (ev.kind == ExactValue_String) {
ac->link_suffix = ev.value_string;
- if (!is_foreign_name_valid(ac->link_suffix)) {
+ if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) {
error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
}
} else {
@@ -3774,7 +3808,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string;
- if (!is_foreign_name_valid(ac->link_prefix)) {
+ if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) {
error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix));
}
} else {
@@ -3785,7 +3819,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
ac->link_suffix = ev.value_string;
- if (!is_foreign_name_valid(ac->link_suffix)) {
+ if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) {
error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
}
} else {
@@ -4532,7 +4566,9 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
case_end;
case_ast_node(fb, ForeignBlockDecl, decl);
- check_add_foreign_block_decl(c, decl);
+ if (curr_file != nullptr) {
+ array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl);
+ }
case_end;
default:
@@ -4548,6 +4584,14 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
// NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source
if (curr_file == nullptr) {
+ // For 'foreign' block statements that are not in file scope.
+ for_array(decl_index, nodes) {
+ Ast *decl = nodes[decl_index];
+ if (decl->kind == Ast_ForeignBlockDecl) {
+ check_add_foreign_block_decl(c, decl);
+ }
+ }
+
for_array(decl_index, nodes) {
Ast *decl = nodes[decl_index];
if (decl->kind == Ast_WhenStmt) {
@@ -4934,12 +4978,18 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
}
- if (import_name.len == 0) {
+ if (is_blank_ident(import_name) && !is_blank_ident(id->import_name.string)) {
String invalid_name = id->fullpath;
invalid_name = get_invalid_import_name(invalid_name);
- error(id->token, "Import name %.*s, is not a valid identifier. Perhaps you want to reference the package by a different name like this: import <new_name> \"%.*s\" ", LIT(invalid_name), LIT(invalid_name));
- error(token, "Import name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
+ ERROR_BLOCK();
+
+ if (id->import_name.string.len > 0) {
+ error(token, "Import name '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
+ } else {
+ error(id->token, "Import name '%.*s' is not a valid identifier", LIT(invalid_name));
+ error_line("\tSuggestion: Rename the directory or explicitly set an import name like this 'import <new_name> %.*s'", LIT(id->relpath.string));
+ }
} else {
GB_ASSERT(id->import_name.pos.line != 0);
id->import_name.string = import_name;
@@ -5218,9 +5268,9 @@ gb_internal bool collect_file_decl(CheckerContext *ctx, Ast *decl) {
case_end;
case_ast_node(fb, ForeignBlockDecl, decl);
- if (check_add_foreign_block_decl(ctx, decl)) {
- return true;
- }
+ GB_ASSERT(ctx->collect_delayed_decls);
+ decl->state_flags |= StateFlag_BeenHandled;
+ array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl);
case_end;
case_ast_node(ws, WhenStmt, decl);
@@ -5503,8 +5553,6 @@ gb_internal void check_import_entities(Checker *c) {
for_array(i, pkg->files) {
AstFile *f = pkg->files[i];
reset_checker_context(&ctx, f, &untyped);
- ctx.collect_delayed_decls = false;
-
correct_type_aliases_in_scope(&ctx, pkg->scope);
}
@@ -5512,6 +5560,17 @@ gb_internal void check_import_entities(Checker *c) {
AstFile *f = pkg->files[i];
reset_checker_context(&ctx, f, &untyped);
+ ctx.collect_delayed_decls = true;
+ for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) {
+ check_add_foreign_block_decl(&ctx, decl);
+ }
+ array_clear(&f->delayed_decls_queues[AstDelayQueue_ForeignBlock]);
+ }
+
+ for_array(i, pkg->files) {
+ AstFile *f = pkg->files[i];
+ reset_checker_context(&ctx, f, &untyped);
+
for (Ast *expr : f->delayed_decls_queues[AstDelayQueue_Expr]) {
Operand o = {};
check_expr(&ctx, &o, expr);
@@ -6095,6 +6154,11 @@ gb_internal void check_deferred_procedures(Checker *c) {
case DeferredProcedure_in_out_by_ptr: attribute = "deferred_in_out_by_ptr"; break;
}
+ if (src == dst) {
+ error(src->token, "'%.*s' cannot be used as its own %s", LIT(dst->token.string), attribute);
+ continue;
+ }
+
if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) {
error(src->token, "'%s' cannot be used with a polymorphic procedure", attribute);
continue;
@@ -6465,12 +6529,13 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("check scope usage");
for (auto const &entry : c->info.files) {
AstFile *f = entry.value;
- u64 vet_flags = build_context.vet_flags;
- if (f->vet_flags_set) {
- vet_flags = f->vet_flags;
- }
+ u64 vet_flags = ast_file_vet_flags(f);
check_scope_usage(c, f->scope, vet_flags);
}
+ for (auto const &entry : c->info.packages) {
+ AstPackage *pkg = entry.value;
+ check_scope_usage_internal(c, pkg->scope, 0, true);
+ }
TIME_SECTION("add basic type information");
// Add "Basic" type information
diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp
index ef07938c7..2dfd570e4 100644
--- a/src/checker_builtin_procs.hpp
+++ b/src/checker_builtin_procs.hpp
@@ -99,6 +99,7 @@ enum BuiltinProcId {
BuiltinProc_prefetch_write_instruction,
BuiltinProc_prefetch_write_data,
+BuiltinProc__atomic_begin,
BuiltinProc_atomic_type_is_lock_free,
BuiltinProc_atomic_thread_fence,
BuiltinProc_atomic_signal_fence,
@@ -124,6 +125,7 @@ enum BuiltinProcId {
BuiltinProc_atomic_compare_exchange_strong_explicit,
BuiltinProc_atomic_compare_exchange_weak,
BuiltinProc_atomic_compare_exchange_weak_explicit,
+BuiltinProc__atomic_end,
BuiltinProc_fixed_point_mul,
BuiltinProc_fixed_point_div,
@@ -313,6 +315,8 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_map_info,
BuiltinProc_type_map_cell_info,
+ BuiltinProc_type_has_shared_fields,
+
BuiltinProc__type_end,
BuiltinProc_procedure_of,
@@ -436,6 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
+ {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
@@ -461,6 +466,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
{STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
+ {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -647,6 +653,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+ {STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
diff --git a/src/entity.cpp b/src/entity.cpp
index db6ffdd52..0c4a20df4 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -104,6 +104,7 @@ enum ParameterValueKind {
ParameterValue_Constant,
ParameterValue_Nil,
ParameterValue_Location,
+ ParameterValue_Expression,
ParameterValue_Value,
};
diff --git a/src/gb/gb.h b/src/gb/gb.h
index 38dabc9bd..1fef4b4f5 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -39,7 +39,7 @@ extern "C" {
#endif
#endif
-#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) || defined(__aarch64__)
+#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64)
#ifndef GB_ARCH_64_BIT
#define GB_ARCH_64_BIT 1
#endif
@@ -144,6 +144,13 @@ extern "C" {
#define GB_CACHE_LINE_SIZE 64
#endif
+#elif defined(__riscv)
+ #ifndef GB_CPU_RISCV
+ #define GB_CPU_RISCV 1
+ #endif
+ #ifndef GB_CACHE_LINE_SIZE
+ #define GB_CACHE_LINE_SIZE 64
+ #endif
#else
#error Unknown CPU Type
#endif
@@ -2562,7 +2569,7 @@ gb_inline void *gb_memcopy(void *dest, void const *source, isize n) {
void *dest_copy = dest;
__asm__ __volatile__("rep movsb" : "+D"(dest_copy), "+S"(source), "+c"(n) : : "memory");
-#elif defined(GB_CPU_ARM)
+#elif defined(GB_CPU_ARM) || defined(GB_CPU_RISCV)
u8 *s = cast(u8 *)source;
u8 *d = cast(u8 *)dest;
for (isize i = 0; i < n; i++) {
@@ -3188,11 +3195,11 @@ void gb_affinity_init(gbAffinity *a) {
a->core_count = 1;
a->threads_per_core = 1;
- if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) {
+ if (sysctlbyname("kern.smp.cpus", &count, &count_size, NULL, 0) == 0) {
if (count > 0) {
a->thread_count = count;
// Get # of physical cores
- if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) {
+ if (sysctlbyname("kern.smp.cores", &count, &count_size, NULL, 0) == 0) {
if (count > 0) {
a->core_count = count;
a->threads_per_core = a->thread_count / count;
@@ -3203,6 +3210,14 @@ void gb_affinity_init(gbAffinity *a) {
}
}
}
+ } else if (sysctlbyname("hw.ncpu", &count, &count_size, NULL, 0) == 0) {
+ // SMP disabled or unavailable.
+ if (count > 0) {
+ a->is_accurate = true;
+ a->thread_count = count;
+ a->core_count = count;
+ a->threads_per_core = 1;
+ }
}
}
@@ -6267,6 +6282,12 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
}
+#elif defined(__riscv)
+ gb_inline u64 gb_rdtsc(void) {
+ u64 result = 0;
+ __asm__ volatile("rdcycle %0" : "=r"(result));
+ return result;
+ }
#else
#warning "gb_rdtsc not supported"
gb_inline u64 gb_rdtsc(void) { return 0; }
diff --git a/src/linker.cpp b/src/linker.cpp
index faca28932..500fead69 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -548,14 +548,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
// available at runtime wherever the executable is run, so we make require those to be
// local to the executable (unless the system collection is used, in which case we search
// the system library paths for the library file).
- if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) {
- // static libs and object files, absolute full path relative to the file in which the lib was imported from
+ if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) {
lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib));
- } else if (string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) {
- // dynamic lib, relative path to executable
- // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
- // at runtime to the executable
- lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib));
} else {
// dynamic or static system lib, just link regularly searching system library paths
lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
@@ -643,6 +637,16 @@ gb_internal i32 linker_stage(LinkerData *gen) {
}
}
+ if (!build_context.no_rpath) {
+ // Set the rpath to the $ORIGIN/@loader_path (the path of the executable),
+ // so that dynamic libraries are looked for at that path.
+ if (build_context.metrics.os == TargetOs_darwin) {
+ link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path ");
+ } else {
+ link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN ");
+ }
+ }
+
if (!build_context.no_crt) {
platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
if (build_context.metrics.os == TargetOs_darwin) {
diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp
index aa5c4dc60..42086b09d 100644
--- a/src/llvm_abi.cpp
+++ b/src/llvm_abi.cpp
@@ -1257,11 +1257,12 @@ namespace lbAbiWasm {
}
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
- if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
- LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
+ if (type == LLVMIntTypeInContext(c, 128)) {
+ // LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
+ LLVMTypeRef cast_type = nullptr;
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
}
-
+
if (!is_return && lb_sizeof(type) > 8) {
return lb_arg_type_indirect(type, nullptr);
}
@@ -1282,7 +1283,7 @@ namespace lbAbiWasm {
case LLVMPointerTypeKind:
return true;
case LLVMIntegerTypeKind:
- return lb_sizeof(type) <= 8;
+ return lb_sizeof(type) <= 16;
}
return false;
}
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index f852636a6..01ded321e 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -3081,6 +3081,13 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
lbModule *m = entry.value;
m->target_machine = target_machine;
LLVMSetModuleDataLayout(m->mod, LLVMCreateTargetDataLayout(target_machine));
+
+ #if LLVM_VERSION_MAJOR >= 18
+ if (build_context.fast_isel) {
+ LLVMSetTargetMachineFastISel(m->target_machine, true);
+ }
+ #endif
+
array_add(&target_machines, target_machine);
}
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 29d2ccfe6..68f95cb03 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -528,7 +528,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure, TokenPos const &pos);
-gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos);
+gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TypeProc *procedure_type, Ast *call_expression);
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index 6a6b119aa..754bbfca2 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -154,7 +154,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
GB_ASSERT(value_count_ == bt->Struct.fields.count);
auto field_remapping = lb_get_struct_remapping(m, t);
- unsigned values_with_padding_count = LLVMCountStructElementTypes(struct_type);
+ unsigned values_with_padding_count = elem_count;
LLVMValueRef *values_with_padding = gb_alloc_array(permanent_allocator(), LLVMValueRef, values_with_padding_count);
for (unsigned i = 0; i < value_count; i++) {
@@ -722,7 +722,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
}
case ExactValue_Integer:
- if (is_type_pointer(type) || is_type_multi_pointer(type)) {
+ if (is_type_pointer(type) || is_type_multi_pointer(type) || is_type_proc(type)) {
LLVMTypeRef t = lb_type(m, original_type);
LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer);
res.value = LLVMConstIntToPtr(i, t);
diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp
index c896f889d..5cc79dcc8 100644
--- a/src/llvm_backend_debug.cpp
+++ b/src/llvm_backend_debug.cpp
@@ -55,6 +55,16 @@ gb_internal void lb_debug_file_line(lbModule *m, Ast *node, LLVMMetadataRef *fil
}
}
+gb_internal LLVMMetadataRef lb_debug_procedure_parameters(lbModule *m, Type *type) {
+ if (is_type_proc(type)) {
+ return lb_debug_type(m, t_rawptr);
+ }
+ if (type->kind == Type_Tuple && type->Tuple.variables.count == 1) {
+ return lb_debug_procedure_parameters(m, type->Tuple.variables[0]->type);
+ }
+ return lb_debug_type(m, type);
+}
+
gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
i64 size = type_size_of(type); // Check size
gb_unused(size);
@@ -72,13 +82,36 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
parameter_count += 1;
}
}
- LLVMMetadataRef *parameters = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, parameter_count);
- unsigned param_index = 0;
- if (type->Proc.result_count == 0) {
- parameters[param_index++] = nullptr;
- } else {
- parameters[param_index++] = lb_debug_type(m, type->Proc.results);
+ auto parameters = array_make<LLVMMetadataRef>(permanent_allocator(), 0, type->Proc.param_count+type->Proc.result_count+2);
+
+ array_add(&parameters, cast(LLVMMetadataRef)nullptr);
+
+ bool return_is_tuple = false;
+ if (type->Proc.result_count != 0) {
+ Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
+ if (is_type_proc(single_ret)) {
+ single_ret = t_rawptr;
+ }
+ if (is_type_tuple(single_ret) && is_calling_convention_odin(type->Proc.calling_convention)) {
+ LLVMTypeRef actual = lb_type_internal_for_procedures_raw(m, type);
+ actual = LLVMGetReturnType(actual);
+ if (actual == nullptr) {
+ // results were passed as a single pointer
+ parameters[0] = lb_debug_procedure_parameters(m, single_ret);
+ } else {
+ LLVMTypeRef possible = lb_type(m, type->Proc.results);
+ if (possible == actual) {
+ // results were returned directly
+ parameters[0] = lb_debug_procedure_parameters(m, single_ret);
+ } else {
+ // resulsts were returned separately
+ return_is_tuple = true;
+ }
+ }
+ } else {
+ parameters[0] = lb_debug_procedure_parameters(m, single_ret);
+ }
}
LLVMMetadataRef file = nullptr;
@@ -88,8 +121,22 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
if (e->kind != Entity_Variable) {
continue;
}
- parameters[param_index] = lb_debug_type(m, e->type);
- param_index += 1;
+ array_add(&parameters, lb_debug_procedure_parameters(m, e->type));
+ }
+
+
+ if (return_is_tuple) {
+ Type *results = type->Proc.results;
+ GB_ASSERT(results != nullptr && results->kind == Type_Tuple);
+ isize count = results->Tuple.variables.count;
+ parameters[0] = lb_debug_procedure_parameters(m, results->Tuple.variables[count-1]->type);
+ for (isize i = 0; i < count-1; i++) {
+ array_add(&parameters, lb_debug_procedure_parameters(m, results->Tuple.variables[i]->type));
+ }
+ }
+
+ if (type->Proc.calling_convention == ProcCC_Odin) {
+ array_add(&parameters, lb_debug_type(m, t_context_ptr));
}
LLVMDIFlags flags = LLVMDIFlagZero;
@@ -97,7 +144,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
flags = LLVMDIFlagNoReturn;
}
- return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags);
+ return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters.data, cast(unsigned)parameters.count, flags);
}
gb_internal LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
@@ -505,6 +552,48 @@ gb_internal LLVMMetadataRef lb_debug_bitset(lbModule *m, Type *type, String name
return final_decl;
}
+gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) {
+ Type *bt = base_type(type);
+ GB_ASSERT(bt->kind == Type_BitField);
+
+ lb_debug_file_line(m, bt->BitField.node, &file, &line);
+
+ u64 size_in_bits = 8*type_size_of(bt);
+ u32 align_in_bits = 8*cast(u32)type_align_of(bt);
+
+ unsigned element_count = cast(unsigned)bt->BitField.fields.count;
+ LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
+
+ u64 offset_in_bits = 0;
+ for (unsigned i = 0; i < element_count; i++) {
+ Entity *f = bt->BitField.fields[i];
+ u8 bit_size = bt->BitField.bit_sizes[i];
+ GB_ASSERT(f->kind == Entity_Variable);
+ String name = f->token.string;
+ elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line,
+ bit_size, offset_in_bits, 0,
+ LLVMDIFlagZero, lb_debug_type(m, f->type)
+ );
+
+ offset_in_bits += bit_size;
+ }
+
+ LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType(
+ m->debug_builder, scope,
+ cast(char const *)name.text, cast(size_t)name.len,
+ file, line,
+ size_in_bits, align_in_bits,
+ LLVMDIFlagZero,
+ nullptr,
+ elements, element_count,
+ 0,
+ nullptr,
+ "", 0
+ );
+ lb_set_llvm_metadata(m, type, final_decl);
+ return final_decl;
+}
+
gb_internal LLVMMetadataRef lb_debug_enum(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) {
Type *bt = base_type(type);
GB_ASSERT(bt->kind == Type_Enum);
@@ -769,6 +858,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
+ case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0);
case Type_Tuple:
if (type->Tuple.variables.count == 1) {
@@ -854,42 +944,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
lb_debug_type(m, type->Matrix.elem),
subscripts, gb_count_of(subscripts));
}
-
- case Type_BitField: {
- LLVMMetadataRef parent_scope = nullptr;
- LLVMMetadataRef scope = nullptr;
- LLVMMetadataRef file = nullptr;
- unsigned line = 0;
- u64 size_in_bits = 8*cast(u64)type_size_of(type);
- u32 align_in_bits = 8*cast(u32)type_align_of(type);
- LLVMDIFlags flags = LLVMDIFlagZero;
-
- unsigned element_count = cast(unsigned)type->BitField.fields.count;
- LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
-
- u64 offset_in_bits = 0;
- for (unsigned i = 0; i < element_count; i++) {
- Entity *f = type->BitField.fields[i];
- u8 bit_size = type->BitField.bit_sizes[i];
- GB_ASSERT(f->kind == Entity_Variable);
- String name = f->token.string;
- unsigned field_line = 0;
- LLVMDIFlags field_flags = LLVMDIFlagZero;
- elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line,
- bit_size, offset_in_bits, offset_in_bits,
- field_flags, lb_debug_type(m, f->type)
- );
-
- offset_in_bits += bit_size;
- }
-
-
- return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line,
- size_in_bits, align_in_bits, flags,
- nullptr, elements, element_count, 0, nullptr,
- "", 0
- );
- }
}
GB_PANIC("Invalid type %s", type_to_string(type));
@@ -969,12 +1023,13 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
return lb_debug_struct(m, type, bt, name, scope, file, line);
}
- case Type_Struct: return lb_debug_struct(m, type, base_type(type), name, scope, file, line);
+ case Type_Struct: return lb_debug_struct(m, type, bt, name, scope, file, line);
case Type_Slice: return lb_debug_slice(m, type, name, scope, file, line);
case Type_DynamicArray: return lb_debug_dynamic_array(m, type, name, scope, file, line);
case Type_Union: return lb_debug_union(m, type, name, scope, file, line);
case Type_BitSet: return lb_debug_bitset(m, type, name, scope, file, line);
case Type_Enum: return lb_debug_enum(m, type, name, scope, file, line);
+ case Type_BitField: return lb_debug_bitfield(m, type, name, scope, file, line);
}
}
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp
index c2707612a..58467db2e 100644
--- a/src/llvm_backend_expr.cpp
+++ b/src/llvm_backend_expr.cpp
@@ -136,6 +136,11 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
switch (op) {
case Token_Xor:
opv = LLVMBuildNot(p->builder, v, "");
+ if (is_type_bit_set(elem_type)) {
+ ExactValue ev_mask = exact_bit_set_all_set_mask(elem_type);
+ lbValue mask = lb_const_value(p->module, elem_type, ev_mask);
+ opv = LLVMBuildAnd(p->builder, opv, mask.value, "");
+ }
break;
case Token_Sub:
if (is_type_float(elem_type)) {
@@ -176,8 +181,14 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
if (op == Token_Xor) {
lbValue cmp = {};
- cmp.value = LLVMBuildNot(p->builder, x.value, "");
cmp.type = x.type;
+ if (is_type_bit_set(x.type)) {
+ ExactValue ev_mask = exact_bit_set_all_set_mask(x.type);
+ lbValue mask = lb_const_value(p->module, x.type, ev_mask);
+ cmp.value = LLVMBuildXor(p->builder, x.value, mask.value, "");
+ } else {
+ cmp.value = LLVMBuildNot(p->builder, x.value, "");
+ }
return lb_emit_conv(p, cmp, type);
}
@@ -694,31 +705,37 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type
lbAddr res = lb_add_local_generated(p, type, true);
- i64 row_count = mt->Matrix.row_count;
- i64 column_count = mt->Matrix.column_count;
- TEMPORARY_ALLOCATOR_GUARD();
-
- auto srcs = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
- auto dsts = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
-
- for (i64 j = 0; j < column_count; j++) {
- for (i64 i = 0; i < row_count; i++) {
- lbValue src = lb_emit_matrix_ev(p, m, i, j);
- array_add(&srcs, src);
- }
- }
-
- for (i64 j = 0; j < column_count; j++) {
- for (i64 i = 0; i < row_count; i++) {
- lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count);
- array_add(&dsts, dst);
- }
- }
-
- GB_ASSERT(srcs.count == dsts.count);
- for_array(i, srcs) {
- lb_emit_store(p, dsts[i], srcs[i]);
- }
+ GB_ASSERT(type_size_of(type) == type_size_of(m.type));
+
+ lbValue m_ptr = lb_address_from_load_or_generate_local(p, m);
+ lbValue n = lb_const_int(p->module, t_int, type_size_of(type));
+ lb_mem_copy_non_overlapping(p, res.addr, m_ptr, n);
+
+ // i64 row_count = mt->Matrix.row_count;
+ // i64 column_count = mt->Matrix.column_count;
+ // TEMPORARY_ALLOCATOR_GUARD();
+
+ // auto srcs = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
+ // auto dsts = array_make<lbValue>(temporary_allocator(), 0, row_count*column_count);
+
+ // for (i64 j = 0; j < column_count; j++) {
+ // for (i64 i = 0; i < row_count; i++) {
+ // lbValue src = lb_emit_matrix_ev(p, m, i, j);
+ // array_add(&srcs, src);
+ // }
+ // }
+
+ // for (i64 j = 0; j < column_count; j++) {
+ // for (i64 i = 0; i < row_count; i++) {
+ // lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count);
+ // array_add(&dsts, dst);
+ // }
+ // }
+
+ // GB_ASSERT(srcs.count == dsts.count);
+ // for_array(i, srcs) {
+ // lb_emit_store(p, dsts[i], srcs[i]);
+ // }
return lb_addr_load(p, res);
}
@@ -3434,8 +3451,14 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
switch (expr->kind) {
case_ast_node(bl, BasicLit, expr);
+ if (type != nullptr && type->Named.name == "Error") {
+ Entity *e = type->Named.type_name;
+ if (e->pkg && e->pkg->name == "os") {
+ return lb_const_nil(p->module, type);
+ }
+ }
TokenPos pos = bl->token.pos;
- GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]));
+ GB_PANIC("Non-constant basic literal %s - %.*s (%s)", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]), type_to_string(type));
case_end;
case_ast_node(bd, BasicDirective, expr);
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index e850d3364..d84599eb0 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -699,7 +699,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
}
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
- lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
+ GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Location);
+ GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Expression);
+ lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, nullptr, nullptr);
lb_addr_store(p, res, c);
}
@@ -3420,7 +3422,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
}
-gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos) {
+gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TypeProc *procedure_type, Ast* call_expression) {
switch (param_value.kind) {
case ParameterValue_Constant:
if (is_type_constant_type(parameter_type)) {
@@ -3446,8 +3448,60 @@ gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type,
if (p->entity != nullptr) {
proc_name = p->entity->token.string;
}
+
+ ast_node(ce, CallExpr, call_expression);
+ TokenPos pos = ast_token(ce->proc).pos;
+
return lb_emit_source_code_location_as_global(p, proc_name, pos);
}
+ case ParameterValue_Expression:
+ {
+ Ast *orig = param_value.original_ast_expr;
+ if (orig->kind == Ast_BasicDirective) {
+ gbString expr = expr_to_string(call_expression, temporary_allocator());
+ return lb_const_string(p->module, make_string_c(expr));
+ }
+
+ isize param_idx = -1;
+ String param_str = {0};
+ {
+ Ast *call = unparen_expr(orig);
+ GB_ASSERT(call->kind == Ast_CallExpr);
+ ast_node(ce, CallExpr, call);
+ GB_ASSERT(ce->proc->kind == Ast_BasicDirective);
+ GB_ASSERT(ce->args.count == 1);
+ Ast *target = ce->args[0];
+ GB_ASSERT(target->kind == Ast_Ident);
+ String target_str = target->Ident.token.string;
+
+ param_idx = lookup_procedure_parameter(procedure_type, target_str);
+ param_str = target_str;
+ }
+ GB_ASSERT(param_idx >= 0);
+
+
+ Ast *target_expr = nullptr;
+ ast_node(ce, CallExpr, call_expression);
+
+ if (ce->split_args->positional.count > param_idx) {
+ target_expr = ce->split_args->positional[param_idx];
+ }
+
+ for_array(i, ce->split_args->named) {
+ Ast *arg = ce->split_args->named[i];
+ ast_node(fv, FieldValue, arg);
+ GB_ASSERT(fv->field->kind == Ast_Ident);
+ String name = fv->field->Ident.token.string;
+ if (name == param_str) {
+ target_expr = fv->value;
+ break;
+ }
+ }
+
+ gbString expr = expr_to_string(target_expr, temporary_allocator());
+ return lb_const_string(p->module, make_string_c(expr));
+ }
+
case ParameterValue_Value:
return lb_build_expr(p, param_value.ast_value);
}
@@ -3739,8 +3793,6 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
}
}
- TokenPos pos = ast_token(ce->proc).pos;
-
if (pt->params != nullptr) {
isize min_count = pt->params->Tuple.variables.count;
@@ -3764,7 +3816,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
args[arg_index] = lb_const_nil(p->module, e->type);
break;
case Entity_Variable:
- args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos);
+ args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pt, expr);
break;
case Entity_Constant:
diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp
index f2fe4f7dc..df3d4bc03 100644
--- a/src/llvm_backend_stmt.cpp
+++ b/src/llvm_backend_stmt.cpp
@@ -1404,6 +1404,10 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo
}
+ if (is_typeid) {
+ return false;
+ }
+
return true;
}
@@ -2195,8 +2199,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
// and `LLVMConstIntGetZExtValue()` calls below will be valid and `LLVMInstructionEraseFromParent()`
// will target the correct (& only) branch statement
-
- if (cond.value && LLVMIsConstant(cond.value)) {
+ if (cond.value && LLVMIsAConstantInt(cond.value)) {
// NOTE(bill): Do a compile time short circuit for when the condition is constantly known.
// This done manually rather than relying on the SSA passes because sometimes the SSA passes
// miss some even if they are constantly known, especially with few optimization passes.
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index 638170bfc..9d4505bb0 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -826,7 +826,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
if (t->Struct.soa_kind != StructSoa_None) {
- Type *kind_type = get_struct_field_type(tag_type, 10);
+ Type *kind_type = get_struct_field_type(tag_type, 7);
lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind));
LLVMValueRef soa_type = get_type_info_ptr(m, t->Struct.soa_elem);
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index 68c1e9d1e..f63c42ab9 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -263,7 +263,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
if (is_type_simd_vector(src) && is_type_simd_vector(dst)) {
res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), "");
return res;
- } else if (is_type_array_like(src) && is_type_simd_vector(dst)) {
+ } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) {
unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst));
lbValue ptr = lb_address_from_load_or_generate_local(p, value);
if (lb_try_update_alignment(ptr, align)) {
diff --git a/src/main.cpp b/src/main.cpp
index 5131bdc21..a969e32a9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -325,6 +325,7 @@ enum BuildFlagKind {
BuildFlag_NoTypeAssert,
BuildFlag_NoDynamicLiterals,
BuildFlag_NoCRT,
+ BuildFlag_NoRPath,
BuildFlag_NoEntryPoint,
BuildFlag_UseLLD,
BuildFlag_UseSeparateModules,
@@ -339,12 +340,14 @@ enum BuildFlagKind {
BuildFlag_VetUnused,
BuildFlag_VetUnusedImports,
BuildFlag_VetUnusedVariables,
+ BuildFlag_VetUnusedProcedures,
BuildFlag_VetUsingStmt,
BuildFlag_VetUsingParam,
BuildFlag_VetStyle,
BuildFlag_VetSemicolon,
BuildFlag_VetCast,
BuildFlag_VetTabs,
+ BuildFlag_VetPackages,
BuildFlag_CustomAttribute,
BuildFlag_IgnoreUnknownAttributes,
@@ -389,6 +392,7 @@ enum BuildFlagKind {
BuildFlag_PrintLinkerFlags,
// internal use only
+ BuildFlag_InternalFastISel,
BuildFlag_InternalIgnoreLazy,
BuildFlag_InternalIgnoreLLVMBuild,
BuildFlag_InternalIgnorePanic,
@@ -507,7 +511,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check);
- add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test);
+ add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test | Command_doc);
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check);
@@ -532,6 +536,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
@@ -544,6 +549,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
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);
+ add_flag(&build_flags, BuildFlag_VetUnusedProcedures, str_lit("vet-unused-procedures"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUnusedImports, str_lit("vet-unused-imports"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check);
@@ -552,6 +558,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
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_VetPackages, str_lit("vet-packages"), BuildFlagParam_String, 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);
@@ -594,6 +601,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build);
+ add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
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);
@@ -1181,6 +1189,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoCRT:
build_context.no_crt = true;
break;
+ case BuildFlag_NoRPath:
+ build_context.no_rpath = true;
+ break;
case BuildFlag_NoEntryPoint:
build_context.no_entry_point = true;
break;
@@ -1213,6 +1224,36 @@ gb_internal bool parse_build_flags(Array<String> args) {
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_VetUnusedProcedures:
+ build_context.vet_flags |= VetFlag_UnusedProcedures;
+ if (!set_flags[BuildFlag_VetPackages]) {
+ gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name));
+ bad_flags = true;
+ }
+ break;
+
+ case BuildFlag_VetPackages:
+ {
+ GB_ASSERT(value.kind == ExactValue_String);
+ String val = value.value_string;
+ String_Iterator it = {val, 0};
+ for (;;) {
+ String pkg = string_split_iterator(&it, ',');
+ if (pkg.len == 0) {
+ break;
+ }
+
+ pkg = string_trim_whitespace(pkg);
+ if (!string_is_valid_identifier(pkg)) {
+ gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(pkg));
+ bad_flags = true;
+ continue;
+ }
+
+ string_set_add(&build_context.vet_packages, pkg);
+ }
+ }
+ break;
case BuildFlag_CustomAttribute:
{
@@ -1227,7 +1268,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
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));
+ gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(attr));
bad_flags = true;
continue;
}
@@ -1408,6 +1449,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
build_context.print_linker_flags = true;
break;
+ case BuildFlag_InternalFastISel:
+ build_context.fast_isel = true;
+ break;
case BuildFlag_InternalIgnoreLazy:
build_context.ignore_lazy = true;
break;
@@ -2154,6 +2198,12 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(1, "-doc-format");
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
print_usage_line(0, "");
+
+ print_usage_line(1, "-out:<filepath>");
+ print_usage_line(2, "Sets the base name of the resultig .odin-doc file.");
+ print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'.");
+ print_usage_line(2, "Example: -out:foo");
+ print_usage_line(0, "");
}
if (run_or_build) {
@@ -2268,6 +2318,7 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Sets the build mode.");
print_usage_line(2, "Available options:");
print_usage_line(3, "-build-mode:exe Builds as an executable.");
+ print_usage_line(3, "-build-mode:test Builds as an executable that executes tests.");
print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
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.");
@@ -2309,6 +2360,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, "");
+ print_usage_line(1, "-no-rpath");
+ print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory.");
+ print_usage_line(0, "");
+
print_usage_line(1, "-no-thread-local");
print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
print_usage_line(0, "");
@@ -2343,7 +2398,7 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(0, "");
print_usage_line(1, "-vet-unused");
- print_usage_line(2, "Checks for unused declarations.");
+ print_usage_line(2, "Checks for unused declarations (variables and imports).");
print_usage_line(0, "");
print_usage_line(1, "-vet-unused-variables");
@@ -2385,6 +2440,16 @@ gb_internal void print_show_help(String const arg0, String const &command) {
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, "");
+
+ print_usage_line(1, "-vet-packages:<comma-separated-strings>");
+ print_usage_line(2, "Sets which packages by name will be vetted.");
+ print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set.");
+ print_usage_line(0, "");
+
+ print_usage_line(1, "-vet-unused-procedures");
+ print_usage_line(2, "Checks for unused procedures.");
+ print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags.");
+ print_usage_line(0, "");
}
if (check) {
@@ -3129,6 +3194,9 @@ int main(int arg_count, char const **arg_ptr) {
build_context.command = command;
+ string_set_init(&build_context.custom_attributes);
+ string_set_init(&build_context.vet_packages);
+
if (!parse_build_flags(args)) {
return 1;
}
@@ -3252,6 +3320,12 @@ int main(int arg_count, char const **arg_ptr) {
gb_printf_err("missing required target feature: \"%.*s\", enable it by setting a different -microarch or explicitly adding it through -target-features\n", LIT(disabled));
gb_exit(1);
}
+
+ // NOTE(laytan): some weird errors on LLVM 14 that LLVM 17 fixes.
+ if (LLVM_VERSION_MAJOR < 17) {
+ gb_printf_err("Invalid LLVM version %s, RISC-V targets require at least LLVM 17\n", LLVM_VERSION_STRING);
+ gb_exit(1);
+ }
}
if (build_context.show_debug_messages) {
diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h
index 899583143..b0fd22a23 100644
--- a/src/microsoft_craziness.h
+++ b/src/microsoft_craziness.h
@@ -684,8 +684,14 @@ gb_internal void find_visual_studio_paths_from_env_vars(Find_Result *result) {
? str_lit("lib\\x64\\")
: str_lit("lib\\x86\\");
- result->vs_exe_path = mc_concat(vctid, exe);
- result->vs_library_path = mc_concat(vctid, lib);
+ if (string_ends_with(vctid, str_lit("\\"))) {
+ result->vs_exe_path = mc_concat(vctid, exe);
+ result->vs_library_path = mc_concat(vctid, lib);
+ } else {
+ result->vs_exe_path = mc_concat(vctid, str_lit("\\"), exe);
+ result->vs_library_path = mc_concat(vctid, str_lit("\\"), lib);
+ }
+
vs_found = true;
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 5796012d9..520a23c5a 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1,10 +1,28 @@
#include "parser_pos.cpp"
+gb_internal bool in_vet_packages(AstFile *file) {
+ if (file == nullptr) {
+ return true;
+ }
+ if (file->pkg == nullptr) {
+ return true;
+ }
+ if (build_context.vet_packages.entries.count == 0) {
+ return true;
+ }
+ return string_set_exists(&build_context.vet_packages, file->pkg->name);
+}
+
gb_internal u64 ast_file_vet_flags(AstFile *f) {
if (f != nullptr && f->vet_flags_set) {
return f->vet_flags;
}
- return build_context.vet_flags;
+
+ bool found = in_vet_packages(f);
+ if (found) {
+ return build_context.vet_flags;
+ }
+ return 0;
}
gb_internal bool ast_file_vet_style(AstFile *f) {
@@ -1921,6 +1939,9 @@ gb_internal Array<Ast *> parse_enum_field_list(AstFile *f) {
f->curr_token.kind != Token_EOF) {
CommentGroup *docs = f->lead_comment;
CommentGroup *comment = nullptr;
+
+ parse_enforce_tabs(f);
+
Ast *name = parse_value(f);
Ast *value = nullptr;
if (f->curr_token.kind == Token_Eq) {
@@ -2259,6 +2280,7 @@ gb_internal Array<Ast *> parse_union_variant_list(AstFile *f) {
auto variants = array_make<Ast *>(ast_allocator(f));
while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) {
+ parse_enforce_tabs(f);
Ast *type = parse_type(f);
if (type->kind != Ast_BadExpr) {
array_add(&variants, type);
@@ -4274,6 +4296,7 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_Colon &&
f->curr_token.kind != Token_EOF) {
+ if (!is_signature) parse_enforce_tabs(f);
u32 flags = parse_field_prefixes(f);
Ast *param = parse_var_type(f, allow_ellipsis, allow_typeid_token);
if (param->kind == Ast_Ellipsis) {
@@ -4363,6 +4386,8 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
f->curr_token.kind != Token_EOF &&
f->curr_token.kind != Token_Semicolon) {
CommentGroup *docs = f->lead_comment;
+
+ if (!is_signature) parse_enforce_tabs(f);
u32 set_flags = parse_field_prefixes(f);
Token tag = {};
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
@@ -4532,6 +4557,10 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
return ast_bad_stmt(f, f->curr_token, f->curr_token);
}
+ Ast *top_if_stmt = nullptr;
+
+ Ast *prev_if_stmt = nullptr;
+if_else_chain:;
Token token = expect_token(f, Token_if);
Ast *init = nullptr;
Ast *cond = nullptr;
@@ -4573,12 +4602,24 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
ignore_strict_style = true;
}
skip_possible_newline_for_literal(f, ignore_strict_style);
+
+ Ast *curr_if_stmt = ast_if_stmt(f, token, init, cond, body, nullptr);
+ if (top_if_stmt == nullptr) {
+ top_if_stmt = curr_if_stmt;
+ }
+ if (prev_if_stmt != nullptr) {
+ prev_if_stmt->IfStmt.else_stmt = curr_if_stmt;
+ }
+
if (f->curr_token.kind == Token_else) {
Token else_token = expect_token(f, Token_else);
switch (f->curr_token.kind) {
case Token_if:
- else_stmt = parse_if_stmt(f);
- break;
+ // NOTE(bill): Instead of relying on recursive descent for an if-else chain
+ // we can just inline the tail-recursion manually with a simple loop like
+ // construct using a `goto`
+ prev_if_stmt = curr_if_stmt;
+ goto if_else_chain;
case Token_OpenBrace:
else_stmt = parse_block_stmt(f, false);
break;
@@ -4593,7 +4634,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) {
}
}
- return ast_if_stmt(f, token, init, cond, body, else_stmt);
+ curr_if_stmt->IfStmt.else_stmt = else_stmt;
+
+ return top_if_stmt;
}
gb_internal Ast *parse_when_stmt(AstFile *f) {
@@ -4924,7 +4967,7 @@ gb_internal Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
}
if (f->in_when_statement) {
- syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '//+build' tags");
+ syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '#+build' tags");
}
if (kind != ImportDecl_Standard) {
@@ -5312,6 +5355,12 @@ gb_internal Ast *parse_stmt(AstFile *f) {
s = ast_empty_stmt(f, token);
expect_semicolon(f);
return s;
+
+ case Token_FileTag:
+ // This is always an error because all valid file tags will have been processed in `parse_file` already.
+ // Any remaining file tags must be past the package line and thus invalid.
+ syntax_error(token, "Lines starting with #+ (file tags) are only allowed before the package line.");
+ return ast_bad_stmt(f, token, f->curr_token);
}
// Error correction statements
@@ -5347,16 +5396,12 @@ gb_internal Ast *parse_stmt(AstFile *f) {
}
-
-gb_internal u64 check_vet_flags(AstFile *file) {
- if (file && file->vet_flags_set) {
- return file->vet_flags;
+gb_internal void parse_enforce_tabs(AstFile *f) {
+ // Checks to see if tabs have been used for indentation
+ if ((ast_file_vet_flags(f) & VetFlag_Tabs) == 0) {
+ return;
}
- 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) {
@@ -5373,6 +5418,10 @@ gb_internal void parse_enforce_tabs(AstFile *f) {
isize len = end-it;
for (isize i = 0; i < len; i++) {
+ if (it[i] == '/') {
+ // ignore comments
+ break;
+ }
if (it[i] == ' ') {
syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation");
break;
@@ -5387,11 +5436,7 @@ gb_internal Array<Ast *> parse_stmt_list(AstFile *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);
- }
+ parse_enforce_tabs(f);
Ast *stmt = parse_stmt(f);
if (stmt && stmt->kind != Ast_EmptyStmt) {
@@ -5902,20 +5947,6 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
return false;
}
- } else {
-#if !defined(GB_SYSTEM_WINDOWS)
- // @NOTE(vassvik): foreign imports of shared libraries that are not in the system collection on
- // linux/mac have to be local to the executable for consistency with shared libraries.
- // Unix does not have a concept of "import library" for shared/dynamic libraries,
- // so we need to pass the relative path to the linker, and add the current
- // working directory of the exe to the library search paths.
- // Static libraries can be linked directly with the full pathname
- //
- if (node->kind == Ast_ForeignImportDecl && (string_ends_with(file_str, str_lit(".so")) || string_contains_string(file_str, str_lit(".so.")))) {
- *path = file_str;
- return true;
- }
-#endif
}
if (is_package_name_reserved(file_str)) {
@@ -6061,7 +6092,7 @@ gb_internal String build_tag_get_token(String s, String *out) {
}
gb_internal bool parse_build_tag(Token token_for_pos, String s) {
- String const prefix = str_lit("+build");
+ String const prefix = str_lit("build");
GB_ASSERT(string_starts_with(s, prefix));
s = string_trim_whitespace(substring(s, prefix.len, s.len));
@@ -6074,6 +6105,10 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
while (s.len > 0) {
bool this_kind_correct = true;
+ bool this_kind_os_seen = false;
+ bool this_kind_arch_seen = false;
+ int num_tokens = 0;
+
do {
String p = string_trim_whitespace(build_tag_get_token(s, &s));
if (p.len == 0) break;
@@ -6099,7 +6134,18 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
TargetOsKind os = get_target_os_from_string(p);
TargetArchKind arch = get_target_arch_from_string(p);
+ num_tokens += 1;
+
+ // Catches 'windows linux', which is an impossible combination.
+ // Also catches usage of more than two things within a comma separated group.
+ if (num_tokens > 2 || (this_kind_os_seen && os != TargetOs_Invalid) || (this_kind_arch_seen && arch != TargetArch_Invalid)) {
+ syntax_error(token_for_pos, "Invalid build tag: Missing ',' before '%.*s'. Format: '#+build linux, windows amd64, darwin'", LIT(p));
+ break;
+ }
+
if (os != TargetOs_Invalid) {
+ this_kind_os_seen = true;
+
GB_ASSERT(arch == TargetArch_Invalid);
if (is_notted) {
this_kind_correct = this_kind_correct && (os != build_context.metrics.os);
@@ -6107,6 +6153,8 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
this_kind_correct = this_kind_correct && (os == build_context.metrics.os);
}
} else if (arch != TargetArch_Invalid) {
+ this_kind_arch_seen = true;
+
if (is_notted) {
this_kind_correct = this_kind_correct && (arch != build_context.metrics.arch);
} else {
@@ -6146,7 +6194,7 @@ gb_internal String vet_tag_get_token(String s, String *out) {
gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
- String const prefix = str_lit("+vet");
+ String const prefix = str_lit("vet");
GB_ASSERT(string_starts_with(s, prefix));
s = string_trim_whitespace(substring(s, prefix.len, s.len));
@@ -6251,7 +6299,7 @@ gb_internal isize calc_decl_count(Ast *decl) {
}
gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s) {
- String const prefix = str_lit("+build-project-name");
+ String const prefix = str_lit("build-project-name");
GB_ASSERT(string_starts_with(s, prefix));
s = string_trim_whitespace(substring(s, prefix.len, s.len));
if (s.len == 0) {
@@ -6295,6 +6343,48 @@ gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s
return any_correct;
}
+gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) {
+ if (string_starts_with(lc, str_lit("build-project-name"))) {
+ if (!parse_build_project_directory_tag(tok, lc)) {
+ return false;
+ }
+ } else if (string_starts_with(lc, str_lit("build"))) {
+ if (!parse_build_tag(tok, lc)) {
+ return false;
+ }
+ } else if (string_starts_with(lc, str_lit("vet"))) {
+ f->vet_flags = parse_vet_tag(tok, lc);
+ f->vet_flags_set = true;
+ } else if (string_starts_with(lc, str_lit("ignore"))) {
+ return false;
+ } else if (string_starts_with(lc, str_lit("private"))) {
+ f->flags |= AstFile_IsPrivatePkg;
+ String command = string_trim_starts_with(lc, str_lit("private "));
+ command = string_trim_whitespace(command);
+ if (lc == "private") {
+ f->flags |= AstFile_IsPrivatePkg;
+ } else if (command == "package") {
+ f->flags |= AstFile_IsPrivatePkg;
+ } else if (command == "file") {
+ f->flags |= AstFile_IsPrivateFile;
+ }
+ } else if (lc == "lazy") {
+ if (build_context.ignore_lazy) {
+ // Ignore
+ } else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) {
+ // Ignore
+ } else {
+ f->flags |= AstFile_IsLazy;
+ }
+ } else if (lc == "no-instrumentation") {
+ f->flags |= AstFile_NoInstrumentation;
+ } else {
+ error(tok, "Unknown tag '%.*s'", LIT(lc));
+ }
+
+ return true;
+}
+
gb_internal bool parse_file(Parser *p, AstFile *f) {
if (f->tokens.count == 0) {
return true;
@@ -6313,9 +6403,34 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
CommentGroup *docs = f->lead_comment;
+ Array<Token> tags = array_make<Token>(temporary_allocator());
+ bool first_invalid_token_set = false;
+ Token first_invalid_token = {};
+
+ while (f->curr_token.kind != Token_package && f->curr_token.kind != Token_EOF) {
+ if (f->curr_token.kind == Token_Comment) {
+ consume_comment_groups(f, f->prev_token);
+ } else if (f->curr_token.kind == Token_FileTag) {
+ array_add(&tags, f->curr_token);
+ advance_token(f);
+ } else {
+ if (!first_invalid_token_set) {
+ first_invalid_token_set = true;
+ first_invalid_token = f->curr_token;
+ }
+
+ advance_token(f);
+ }
+ }
+
if (f->curr_token.kind != Token_package) {
ERROR_BLOCK();
- syntax_error(f->curr_token, "Expected a package declaration at the beginning of the file");
+
+ // The while loop above scanned until it found the package token. If we never
+ // found one, then make this error appear on the first invalid token line.
+ Token t = first_invalid_token_set ? first_invalid_token : f->curr_token;
+ syntax_error(t, "Expected a package declaration at the beginning of the file");
+
// IMPORTANT NOTE(bill): this is technically a race condition with the suggestion, but it's ony a suggession
// so in practice is should be "fine"
if (f->pkg && f->pkg->name != "") {
@@ -6324,18 +6439,16 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
return false;
}
+ // There was an OK package declaration. But there some invalid token was hit before the package declaration.
+ if (first_invalid_token_set) {
+ syntax_error(first_invalid_token, "Expected only comments or lines starting with '#+' before the package declaration");
+ return false;
+ }
+
f->package_token = expect_token(f, Token_package);
if (f->package_token.kind != Token_package) {
return false;
}
- if (docs != nullptr) {
- TokenPos end = token_pos_end(docs->list[docs->list.count-1]);
- if (end.line == f->package_token.pos.line || end.line+1 == f->package_token.pos.line) {
- // Okay
- } else {
- docs = nullptr;
- }
- }
Token package_name = expect_token_after(f, Token_Ident, "package");
if (package_name.kind == Token_Ident) {
@@ -6349,53 +6462,40 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
}
f->package_name = package_name.string;
- if (!f->pkg->is_single_file && docs != nullptr && docs->list.count > 0) {
- for (Token const &tok : docs->list) {
- GB_ASSERT(tok.kind == Token_Comment);
- String str = tok.string;
- if (string_starts_with(str, str_lit("//"))) {
+ // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example
+ // should be respected even when in single file mode.
+ if (!f->pkg->is_single_file) {
+ if (docs != nullptr && docs->list.count > 0) {
+ for (Token const &tok : docs->list) {
+ GB_ASSERT(tok.kind == Token_Comment);
+ String str = tok.string;
+
+ if (!string_starts_with(str, str_lit("//"))) {
+ continue;
+ }
+
String lc = string_trim_whitespace(substring(str, 2, str.len));
- if (lc.len > 0 && lc[0] == '+') {
- if (string_starts_with(lc, str_lit("+build-project-name"))) {
- if (!parse_build_project_directory_tag(tok, lc)) {
- return false;
- }
- } else if (string_starts_with(lc, str_lit("+build"))) {
- if (!parse_build_tag(tok, lc)) {
- return false;
- }
- } else if (string_starts_with(lc, str_lit("+vet"))) {
- f->vet_flags = parse_vet_tag(tok, lc);
- f->vet_flags_set = true;
- } else if (string_starts_with(lc, str_lit("+ignore"))) {
+ if (string_starts_with(lc, str_lit("+"))) {
+ syntax_warning(tok, "'//+' is deprecated: Use '#+' instead");
+ String lt = substring(lc, 1, lc.len);
+ if (parse_file_tag(lt, tok, f) == false) {
return false;
- } else if (string_starts_with(lc, str_lit("+private"))) {
- f->flags |= AstFile_IsPrivatePkg;
- String command = string_trim_starts_with(lc, str_lit("+private "));
- command = string_trim_whitespace(command);
- if (lc == "+private") {
- f->flags |= AstFile_IsPrivatePkg;
- } else if (command == "package") {
- f->flags |= AstFile_IsPrivatePkg;
- } else if (command == "file") {
- f->flags |= AstFile_IsPrivateFile;
- }
- } else if (lc == "+lazy") {
- if (build_context.ignore_lazy) {
- // Ignore
- } else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) {
- // Ignore
- } else {
- f->flags |= AstFile_IsLazy;
- }
- } else if (lc == "+no-instrumentation") {
- f->flags |= AstFile_NoInstrumentation;
- } else {
- warning(tok, "Ignoring unknown tag '%.*s'", LIT(lc));
}
}
}
}
+
+ for (Token const &tok : tags) {
+ GB_ASSERT(tok.kind == Token_FileTag);
+ String str = tok.string;
+
+ if (string_starts_with(str, str_lit("#+"))) {
+ String lt = string_trim_whitespace(substring(str, 2, str.len));
+ if (parse_file_tag(lt, tok, f) == false) {
+ return false;
+ }
+ }
+ }
}
Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment);
@@ -6416,7 +6516,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
}
f->total_file_decl_count += calc_decl_count(stmt);
- if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl) {
+ if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl || stmt->kind == Ast_ForeignBlockDecl) {
f->delayed_decl_count += 1;
}
}
diff --git a/src/parser.hpp b/src/parser.hpp
index 565a8e621..d5117a31e 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -82,6 +82,7 @@ enum AstFileFlag : u32 {
enum AstDelayQueueKind {
AstDelayQueue_Import,
AstDelayQueue_Expr,
+ AstDelayQueue_ForeignBlock,
AstDelayQueue_COUNT,
};
@@ -885,4 +886,7 @@ gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) {
gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind);
gb_internal gbString expr_to_string(Ast *expression);
-gb_internal bool allow_field_separator(AstFile *f); \ No newline at end of file
+gb_internal bool allow_field_separator(AstFile *f);
+
+
+gb_internal void parse_enforce_tabs(AstFile *f); \ No newline at end of file
diff --git a/src/threading.cpp b/src/threading.cpp
index e30a20a06..af8fd803c 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -529,6 +529,9 @@ gb_internal gb_inline void yield_thread(void) {
_mm_pause();
#elif defined(GB_CPU_ARM)
__asm__ volatile ("yield" : : : "memory");
+#elif defined(GB_CPU_RISCV)
+ // I guess?
+ __asm__ volatile ("nop" : : : "memory");
#else
#error Unknown architecture
#endif
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index 4425bee29..53f6135d0 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -2,6 +2,7 @@
TOKEN_KIND(Token_Invalid, "Invalid"), \
TOKEN_KIND(Token_EOF, "EOF"), \
TOKEN_KIND(Token_Comment, "Comment"), \
+ TOKEN_KIND(Token_FileTag, "FileTag"), \
\
TOKEN_KIND(Token__LiteralBegin, ""), \
TOKEN_KIND(Token_Ident, "identifier"), \
@@ -939,6 +940,20 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
if (t->curr_rune == '!') {
token->kind = Token_Comment;
tokenizer_skip_line(t);
+ } else if (t->curr_rune == '+') {
+ token->kind = Token_FileTag;
+
+ // Skip until end of line or until we hit what is probably a comment.
+ // The parsing of tags happens in `parse_file`.
+ while (t->curr_rune != GB_RUNE_EOF) {
+ if (t->curr_rune == '\n') {
+ break;
+ }
+ if (t->curr_rune == '/') {
+ break;
+ }
+ advance_to_next_rune(t);
+ }
}
break;
case '/':
diff --git a/src/types.cpp b/src/types.cpp
index 21dd6ad39..a9a7d6dda 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -1474,6 +1474,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
Type *elem = t->Matrix.elem;
i64 row_count = gb_max(t->Matrix.row_count, 1);
+ i64 column_count = gb_max(t->Matrix.column_count, 1);
bool pop = type_path_push(tp, elem);
if (tp->failure) {
@@ -1491,7 +1492,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) {
// could be maximally aligned but as a compromise, having no padding will be
// beneficial to third libraries that assume no padding
- i64 total_expected_size = row_count*t->Matrix.column_count*elem_size;
+ i64 total_expected_size = row_count*column_count*elem_size;
// i64 min_alignment = prev_pow2(elem_align * row_count);
i64 min_alignment = prev_pow2(total_expected_size);
while (total_expected_size != 0 && (total_expected_size % min_alignment) != 0) {
@@ -1523,12 +1524,15 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) {
i64 stride_in_bytes = 0;
// NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding
- // It would be better for performance to pad each column so that each column
+ // It would be better for performance to pad each column/row so that each column/row
// could be maximally aligned but as a compromise, having no padding will be
// beneficial to third libraries that assume no padding
- i64 row_count = t->Matrix.row_count;
- stride_in_bytes = elem_size*row_count;
-
+
+ if (t->Matrix.is_row_major) {
+ stride_in_bytes = elem_size*t->Matrix.column_count;
+ } else {
+ stride_in_bytes = elem_size*t->Matrix.row_count;
+ }
t->Matrix.stride_in_bytes = stride_in_bytes;
return stride_in_bytes;
}
@@ -2810,8 +2814,14 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
case Type_Union:
if (x->Union.variants.count == y->Union.variants.count &&
- x->Union.custom_align == y->Union.custom_align &&
x->Union.kind == y->Union.kind) {
+
+ if (x->Union.custom_align != y->Union.custom_align) {
+ if (type_align_of(x) != type_align_of(y)) {
+ return false;
+ }
+ }
+
// NOTE(bill): zeroth variant is nullptr
for_array(i, x->Union.variants) {
if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) {
@@ -2827,10 +2837,16 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
x->Struct.is_no_copy == y->Struct.is_no_copy &&
x->Struct.fields.count == y->Struct.fields.count &&
x->Struct.is_packed == y->Struct.is_packed &&
- x->Struct.custom_align == y->Struct.custom_align &&
x->Struct.soa_kind == y->Struct.soa_kind &&
x->Struct.soa_count == y->Struct.soa_count &&
are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) {
+
+ if (x->Struct.custom_align != y->Struct.custom_align) {
+ if (type_align_of(x) != type_align_of(y)) {
+ return false;
+ }
+ }
+
for_array(i, x->Struct.fields) {
Entity *xf = x->Struct.fields[i];
Entity *yf = y->Struct.fields[i];
@@ -4205,7 +4221,11 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_Matrix: {
i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path);
- return stride_in_bytes * t->Matrix.column_count;
+ if (t->Matrix.is_row_major) {
+ return stride_in_bytes * t->Matrix.row_count;
+ } else {
+ return stride_in_bytes * t->Matrix.column_count;
+ }
}
case Type_BitField:
diff --git a/tests/core/bytes/test_core_bytes.odin b/tests/core/bytes/test_core_bytes.odin
index fb3c460aa..7f078c423 100644
--- a/tests/core/bytes/test_core_bytes.odin
+++ b/tests/core/bytes/test_core_bytes.odin
@@ -87,3 +87,11 @@ test_index_byte_zero :: proc(t: ^testing.T) {
}
}
}
+
+@test
+test_last_index_byte_bounds :: proc(t: ^testing.T) {
+ input := "helloworld.odin."
+ assert(len(input) == 16)
+ idx := bytes.last_index_byte(transmute([]byte)(input[:len(input)-1]), '.')
+ testing.expect_value(t, idx, 10)
+} \ No newline at end of file
diff --git a/tests/core/c/libc/test_core_libc_complex_pow.odin b/tests/core/c/libc/test_core_libc_complex_pow.odin
index cd50c8f6a..e308cc171 100644
--- a/tests/core/c/libc/test_core_libc_complex_pow.odin
+++ b/tests/core/c/libc/test_core_libc_complex_pow.odin
@@ -69,18 +69,18 @@ test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, po
complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
result := pow(complex_base, complex_power)
switch n%%4 {
- case 0:
- expected_real = value
- expected_imag = 0.
- case 1:
- expected_real = 0.
- expected_imag = value
- case 2:
- expected_real = -value
- expected_imag = 0.
- case 3:
- expected_real = 0.
- expected_imag = -value
+ case 0:
+ expected_real = value
+ expected_imag = 0.
+ case 1:
+ expected_real = 0.
+ expected_imag = value
+ case 2:
+ expected_real = -value
+ expected_imag = 0.
+ case 3:
+ expected_real = 0.
+ expected_imag = -value
}
testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol)
testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol)
diff --git a/tests/core/container/test_core_bit_array.odin b/tests/core/container/test_core_bit_array.odin
new file mode 100644
index 000000000..8283d73f9
--- /dev/null
+++ b/tests/core/container/test_core_bit_array.odin
@@ -0,0 +1,244 @@
+package test_core_container
+
+import "core:container/bit_array"
+import "core:log"
+import "core:math/rand"
+import "core:slice"
+import "core:testing"
+
+ELEM_BIT_SIZE :: 8 * size_of(u64)
+
+@test
+test_bit_array_bias :: proc(t: ^testing.T) {
+ for bias in -ELEM_BIT_SIZE..=ELEM_BIT_SIZE {
+ M :: 19
+ list := []int{0,1,3,5,7,11,13,17,M}
+
+ ba := bit_array.create(M + bias, bias)
+ defer bit_array.destroy(ba)
+
+ for v, i in list {
+ list[i] = v + bias
+ }
+
+ for i in list {
+ bit_array.set(ba, i)
+ testing.expectf(t, bit_array.get(ba, i),
+ "Expected bit_array<length: %i, bias: %i>[%i] to be true",
+ ba.length, ba.bias, i)
+ }
+
+ seen: [dynamic]int
+ defer delete(seen)
+
+ iter := bit_array.make_iterator(ba)
+ for i in bit_array.iterate_by_set(&iter) {
+ append(&seen, i)
+ }
+
+ testing.expectf(t, slice.equal(list, seen[:]),
+ "Expected bit_array<length: %i, bias: %i> to be: %v, got %v",
+ ba.length, ba.bias, list, seen)
+ }
+}
+
+@test
+test_bit_array_empty_iteration :: proc(t: ^testing.T) {
+ ba: ^bit_array.Bit_Array = &{}
+ defer bit_array.destroy(ba)
+
+ for x in 0..=1 {
+ if x == 1 {
+ // Run the same tests with a created bit_array.
+ ba = bit_array.create(0,0)
+ }
+
+ iter := bit_array.make_iterator(ba)
+ for v, i in bit_array.iterate_by_all(&iter) {
+ log.errorf("Empty bit array had iterable: %v, %i", v, i)
+ }
+
+ iter = bit_array.make_iterator(ba)
+ for i in bit_array.iterate_by_unset(&iter) {
+ log.errorf("Empty bit array had iterable: %v", i)
+ }
+ }
+}
+
+@test
+test_bit_array_biased_max_index :: proc(t: ^testing.T) {
+ for bias in -ELEM_BIT_SIZE..=ELEM_BIT_SIZE {
+ for max_index in 1+bias..<ELEM_BIT_SIZE {
+ length := max_index - bias
+ ba := bit_array.create(max_index, bias)
+ defer bit_array.destroy(ba)
+
+ bit_array.set(ba, max_index - 1)
+
+ expected := max_index - bias
+ testing.expectf(t, ba.length == expected,
+ "Expected bit_array<max_index: %i, bias: %i> length to be: %i, got %i",
+ max_index, bias, expected, ba.length)
+
+ list := make([]int, length)
+ defer delete(list)
+ for i in 0..<len(list) {
+ list[i] = i + bias
+ }
+
+ seen: [dynamic]int
+ defer delete(seen)
+
+ iter := bit_array.make_iterator(ba)
+ for _, i in bit_array.iterate_by_all(&iter) {
+ append(&seen, i)
+ }
+ testing.expectf(t, slice.equal(list[:], seen[:]),
+ "Expected bit_array<max_index: %i, bias: %i> to contain: %v, got %v",
+ max_index, bias, list, seen)
+ }
+ }
+}
+
+@test
+test_bit_array_shrink :: proc(t: ^testing.T) {
+ for bias in -ELEM_BIT_SIZE..=ELEM_BIT_SIZE {
+ ba := bit_array.create(bias, bias)
+ defer bit_array.destroy(ba)
+
+ N :: 3*ELEM_BIT_SIZE
+
+ for i in 0..=N {
+ biased_i := bias + i
+ bit_array.set(ba, biased_i)
+
+ testing.expectf(t, bit_array.get(ba, biased_i),
+ "Expected bit_array<bias: %i>[%i] to be true",
+ ba.bias, biased_i)
+ testing.expectf(t, ba.length == 1 + i,
+ "Expected bit_array<bias: %i> length to be %i, got %i",
+ ba.bias, 1 + i, ba.length)
+
+ legs := 1 + i / ELEM_BIT_SIZE
+
+ testing.expectf(t, len(ba.bits) == legs,
+ "Expected bit_array<bias: %i> to have %i legs with index %i set, had %i legs",
+ ba.bias, legs, biased_i, len(ba.bits))
+
+ bit_array.unset(ba, biased_i)
+
+ if i >= ELEM_BIT_SIZE {
+ // Test shrinking arrays with bits set across two legs.
+ bit_array.set(ba, bias)
+ bit_array.shrink(ba)
+
+ testing.expectf(t, ba.length == 1,
+ "Expected bit_array<bias: %i> length to be 1 after >1 leg shrink, got %i",
+ ba.bias, ba.length)
+ testing.expectf(t, len(ba.bits) == 1,
+ "Expected bit_array<bias: %i> to have one leg after >1 leg shrink, had %i",
+ ba.bias, len(ba.bits))
+
+ bit_array.unset(ba, bias)
+ }
+
+ bit_array.shrink(ba)
+
+ testing.expectf(t, ba.length == 0,
+ "Expected bit_array<bias: %i> length to be zero after final shrink, got %i",
+ ba.bias, ba.length)
+ testing.expectf(t, len(ba.bits) == 0,
+ "Expected bit_array<bias: %i> to have zero legs with index %i set after final shrink, had %i",
+ ba.bias, biased_i, len(ba.bits))
+ }
+ }
+}
+
+@test
+test_bit_array :: proc(t: ^testing.T) {
+ ba := bit_array.create(0, 0)
+ defer bit_array.destroy(ba)
+
+ list_set: [dynamic]int
+ seen_set: [dynamic]int
+ list_unset: [dynamic]int
+ seen_unset: [dynamic]int
+ defer {
+ delete(list_set)
+ delete(seen_set)
+ delete(list_unset)
+ delete(seen_unset)
+ }
+
+ // Setup bits.
+ MAX_INDEX :: 1+16*ELEM_BIT_SIZE
+ for i in 0..=MAX_INDEX {
+ append(&list_unset, i)
+ }
+ for i in 1..=16 {
+ for j in -1..=1 {
+ n := ELEM_BIT_SIZE * i + j
+ bit_array.set(ba, n)
+ append(&list_set, n)
+ }
+ }
+ #reverse for i in list_set {
+ ordered_remove(&list_unset, i)
+ }
+
+ // Test iteration.
+ iter := bit_array.make_iterator(ba)
+ for i in bit_array.iterate_by_set(&iter) {
+ append(&seen_set, i)
+ }
+ testing.expectf(t, slice.equal(list_set[:], seen_set[:]),
+ "Expected set bit_array to be: %v, got %v",
+ list_set, seen_set)
+
+ iter = bit_array.make_iterator(ba)
+ for i in bit_array.iterate_by_unset(&iter) {
+ append(&seen_unset, i)
+ }
+ testing.expectf(t, slice.equal(list_unset[:], seen_unset[:]),
+ "Expected unset bit_array to be: %v, got %v",
+ list_unset, seen_unset)
+
+ // Test getting.
+ for i in list_set {
+ testing.expectf(t, bit_array.get(ba, i),
+ "Expected index %i to be true, got false",
+ i)
+ }
+ for i in list_unset {
+ testing.expectf(t, bit_array.get(ba, i) == false,
+ "Expected index %i to be false, got true",
+ i)
+ }
+
+ // Test flipping bits.
+ rand.shuffle(list_set[:])
+ rand.shuffle(list_unset[:])
+
+ for i in list_set {
+ bit_array.unset(ba, i)
+ testing.expectf(t, bit_array.get(ba, i) == false,
+ "Expected index %i to be false after unsetting, got true",
+ i)
+ }
+
+ for i in list_unset {
+ bit_array.set(ba, i)
+ testing.expectf(t, bit_array.get(ba, i),
+ "Expected index %i to be true after setting, got false",
+ i)
+ }
+
+ // Test clearing.
+ bit_array.clear(ba)
+ iter = bit_array.make_iterator(ba)
+ for i in 0..=MAX_INDEX {
+ testing.expectf(t, bit_array.get(ba, i) == false,
+ "Expected index %i to be false after clearing, got true",
+ i)
+ }
+}
diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin
index b686ef6dd..bdd23691c 100644
--- a/tests/core/container/test_core_rbtree.odin
+++ b/tests/core/container/test_core_rbtree.odin
@@ -187,7 +187,7 @@ validate_rbtree :: proc(t: ^testing.T, tree: ^$T/rb.Tree($Key, $Value)) {
}
verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) {
- testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.")
+ testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.")
if n == nil {
return
}
diff --git a/tests/core/container/test_core_small_array.odin b/tests/core/container/test_core_small_array.odin
index 580df793e..21f35f112 100644
--- a/tests/core/container/test_core_small_array.odin
+++ b/tests/core/container/test_core_small_array.odin
@@ -35,6 +35,25 @@ test_small_array_inject_at :: proc(t: ^testing.T) {
testing.expect(t, slice_equal(small_array.slice(&array), []int { 0, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9, 0 }))
}
+@(test)
+test_small_array_push_back_elems :: proc(t: ^testing.T) {
+ array: small_array.Small_Array(2, int)
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { }))
+ testing.expect(t, small_array.append(&array, 0), "Expected to be able to append to empty small array")
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { 0 }))
+ testing.expect(t, small_array.append(&array, 1, 2) == false, "Expected to fail appending multiple elements beyond capacity of small array")
+ testing.expect(t, small_array.append(&array, 1), "Expected to be able to append to small array")
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { 0, 1 }))
+ testing.expect(t, small_array.append(&array, 1) == false, "Expected to fail appending to full small array")
+ testing.expect(t, small_array.append(&array, 1, 2) == false, "Expected to fail appending multiple elements to full small array")
+ small_array.clear(&array)
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { }))
+ testing.expect(t, small_array.append(&array, 1, 2, 3) == false, "Expected to fail appending multiple elements to empty small array")
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { }))
+ testing.expect(t, small_array.append(&array, 1, 2), "Expected to be able to append multiple elements to empty small array")
+ testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2 }))
+}
+
slice_equal :: proc(a, b: []int) -> bool {
if len(a) != len(b) {
return false
diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin
index 42ac9ce0f..f588d34fa 100644
--- a/tests/core/encoding/json/test_core_json.odin
+++ b/tests/core/encoding/json/test_core_json.odin
@@ -429,7 +429,7 @@ map_with_integer_keys :: proc(t: ^testing.T) {
defer delete_map(my_map2)
unmarshal_err := json.unmarshal(marshaled_data, &my_map2)
- defer for key, item in my_map2 {
+ defer for _, item in my_map2 {
runtime.delete_string(item)
}
testing.expectf(t, unmarshal_err == nil, "Expected `json.unmarshal` to return nil, got %v", unmarshal_err)
diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin
index b29431e10..c0e4329bd 100644
--- a/tests/core/encoding/xml/test_core_xml.odin
+++ b/tests/core/encoding/xml/test_core_xml.odin
@@ -241,7 +241,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
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)
}
}
@@ -250,10 +250,10 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) {
}
if doc.element_count > 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/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin
index f8305f2ea..8fcd6a8a7 100644
--- a/tests/core/flags/test_core_flags.odin
+++ b/tests/core/flags/test_core_flags.odin
@@ -12,6 +12,26 @@ import "core:strings"
import "core:testing"
import "core:time/datetime"
+Custom_Data :: struct {
+ a: int,
+}
+
+@(init)
+init_custom_type_setter :: proc() {
+ // NOTE: This is done here so it can be out of the flow of the
+ // multi-threaded test runner, to prevent any data races that could be
+ // reported by using `-sanitize:thread`.
+ //
+ // Do mind that this means every test here acknowledges the `Custom_Data` type.
+ 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
+ })
+}
+
@(test)
test_no_args :: proc(t: ^testing.T) {
S :: struct {
@@ -1230,9 +1250,6 @@ test_net :: proc(t: ^testing.T) {
@(test)
test_custom_type_setter :: proc(t: ^testing.T) {
Custom_Bool :: distinct bool
- Custom_Data :: struct {
- a: int,
- }
S :: struct {
a: Custom_Data,
@@ -1240,16 +1257,6 @@ test_custom_type_setter :: proc(t: ^testing.T) {
}
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)
diff --git a/tests/core/io/test_core_io.odin b/tests/core/io/test_core_io.odin
new file mode 100644
index 000000000..10c9550cb
--- /dev/null
+++ b/tests/core/io/test_core_io.odin
@@ -0,0 +1,735 @@
+package test_core_io
+
+import "core:bufio"
+import "core:bytes"
+import "core:io"
+import "core:log"
+import "core:os"
+import "core:os/os2"
+import "core:strings"
+import "core:testing"
+
+Passed_Tests :: distinct io.Stream_Mode_Set
+
+_test_stream :: proc(
+ t: ^testing.T,
+ stream: io.Stream,
+ buffer: []u8,
+
+ reading_consumes: bool = false,
+ resets_on_empty: bool = false,
+ do_destroy: bool = true,
+
+ loc := #caller_location
+) -> (passed: Passed_Tests, ok: bool) {
+ // We only test what the stream reports to support.
+
+ mode_set := io.query(stream)
+
+ // Can't feature-test anything if Query isn't supported.
+ testing.expectf(t, .Query in mode_set, "stream does not support .Query: %v", mode_set, loc = loc) or_return
+
+ passed += { .Query }
+
+ size := i64(len(buffer))
+
+ // Do some basic Seek sanity testing.
+ if .Seek in mode_set {
+ pos, err := io.seek(stream, 0, io.Seek_From(-1))
+ testing.expectf(t, err == .Invalid_Whence,
+ "Seek(-1) didn't fail with Invalid_Whence: %v, %v", pos, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, 0, .Start)
+ testing.expectf(t, pos == 0 && err == nil,
+ "Seek Start isn't 0: %v, %v", pos, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, 0, .Current)
+ testing.expectf(t, pos == 0 && err == nil,
+ "Seek Current isn't 0 at the start: %v, %v", pos, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, -1, .Start)
+ testing.expectf(t, err == .Invalid_Offset,
+ "Seek Start-1 wasn't Invalid_Offset: %v, %v", pos, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, -1, .Current)
+ testing.expectf(t, err == .Invalid_Offset,
+ "Seek Current-1 wasn't Invalid_Offset: %v, %v", pos, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, 0, .End)
+ testing.expectf(t, pos == size && err == nil,
+ "Seek End+0 failed: %v != size<%i>, %v", pos, size, err, loc = loc) or_return
+
+ pos, err = io.seek(stream, 0, .Current)
+ testing.expectf(t, pos == size && err == nil,
+ "Seek Current isn't size<%v> at the End: %v, %v", size, pos, err, loc = loc) or_return
+
+ // Seeking past the End is accepted throughout the API.
+ //
+ // It's _reading_ past the End which is erroneous.
+ pos, err = io.seek(stream, 1, .End)
+ testing.expectf(t, pos == size+1 && err == nil,
+ "Seek End+1 failed: %v, %v", pos, err, loc = loc) or_return
+
+ // Reset our position for future tests.
+ pos, err = io.seek(stream, 0, .Start)
+ testing.expectf(t, pos == 0 && err == nil,
+ "Seek Start reset failed: %v, %v", pos, err, loc = loc) or_return
+
+ passed += { .Seek }
+ }
+
+ // Test Size.
+ if .Size in mode_set {
+ api_size, size_err := io.size(stream)
+ testing.expectf(t, api_size == size,
+ "Size reports %v for its size; expected %v", api_size, size, loc = loc) or_return
+ testing.expectf(t, size_err == nil,
+ "Size expected no error: %v", size_err, loc = loc) or_return
+
+ // Ensure Size does not move the underlying pointer from the start.
+ //
+ // Some implementations may use seeking to determine file sizes.
+ if .Seek in mode_set {
+ pos, seek_err := io.seek(stream, 0, .Current)
+ testing.expectf(t, pos == 0 && seek_err == nil,
+ "Size+Seek Current isn't 0 after getting size: %v, %v", pos, seek_err, loc = loc) or_return
+ }
+
+ passed += { .Size }
+ }
+
+ // Test Read_At.
+ if .Read_At in mode_set {
+ // Test reading into an empty buffer.
+ {
+ nil_slice: []u8
+ bytes_read, err := io.read_at(stream, nil_slice, 0)
+ testing.expectf(t, bytes_read == 0 && err == nil,
+ "Read_At into empty slice failed: bytes_read<%v>, %v", bytes_read, err, loc = loc) or_return
+ }
+
+ read_buf, alloc_err := make([]u8, size)
+ testing.expect_value(t, alloc_err, nil, loc = loc) or_return
+ defer delete(read_buf)
+
+ for start in 0..<size {
+ for end in 1+start..<size {
+ subsize := end - start
+ bytes_read, err := io.read_at(stream, read_buf[:subsize], start)
+ testing.expectf(t, i64(bytes_read) == subsize && err == nil,
+ "Read_At(%i) of %v bytes failed: %v, %v", start, subsize, bytes_read, err, loc = loc) or_return
+ testing.expectf(t, bytes.compare(read_buf[:subsize], buffer[start:end]) == 0,
+ "Read_At buffer compare failed: read_buf<%v> != buffer<%v>", read_buf, buffer, loc = loc) or_return
+ }
+ }
+
+ // Test empty streams and EOF.
+ one_buf: [1]u8
+ bytes_read, err := io.read_at(stream, one_buf[:], size)
+ testing.expectf(t, err == .EOF,
+ "Read_At at end of stream failed: %v, %v", bytes_read, err, loc = loc) or_return
+
+ // Make sure size is still sane.
+ if .Size in mode_set {
+ api_size, size_err := io.size(stream)
+ testing.expectf(t, api_size == size,
+ "Read_At+Size reports %v for its size after Read_At tests; expected %v", api_size, size, loc = loc) or_return
+ testing.expectf(t, size_err == nil,
+ "Read_At+Size expected no error: %v", size_err, loc = loc) or_return
+ }
+
+ // Ensure Read_At does not move the underlying pointer from the start.
+ if .Seek in mode_set {
+ pos, seek_err := io.seek(stream, 0, .Current)
+ testing.expectf(t, pos == 0 && seek_err == nil,
+ "Read_At+Seek Current isn't 0 after reading: %v, %v", pos, seek_err, loc = loc) or_return
+ }
+
+ passed += { .Read_At }
+ }
+
+ // Test Read.
+ if .Read in mode_set {
+ // Test reading into an empty buffer.
+ {
+ nil_slice: []u8
+ bytes_read, err := io.read(stream, nil_slice)
+ testing.expectf(t, bytes_read == 0 && err == nil,
+ "Read into empty slice failed: bytes_read<%v>, %v", bytes_read, err, loc = loc) or_return
+ }
+
+ if size > 0 {
+ read_buf, alloc_err := make([]u8, size)
+ testing.expectf(t, alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(read_buf)
+
+ bytes_read, err := io.read(stream, read_buf[:1])
+ testing.expectf(t, bytes_read == 1 && err == nil,
+ "Read 1 byte at start failed: %v, %v", bytes_read, err, loc = loc) or_return
+ testing.expectf(t, read_buf[0] == buffer[0],
+ "Read of first byte failed: read_buf[0]<%v> != buffer[0]<%v>", read_buf[0], buffer[0], loc = loc) or_return
+
+ // Test rolling back the stream one byte then reading it again.
+ if .Seek in mode_set {
+ pos, seek_err := io.seek(stream, -1, .Current)
+ testing.expectf(t, pos == 0 && err == nil,
+ "Read+Seek Current-1 reset to 0 failed: %v, %v", pos, seek_err, loc = loc) or_return
+
+ bytes_read, err = io.read(stream, read_buf[:1])
+ testing.expectf(t, bytes_read == 1 && err == nil,
+ "Read 1 byte at start after Seek reset failed: %v, %v", bytes_read, err, loc = loc) or_return
+ testing.expectf(t, read_buf[0] == buffer[0] ,
+ "re-Read of first byte failed: read_buf[0]<%v> != buffer[0]<%v>", read_buf[0], buffer[0], loc = loc) or_return
+ }
+
+ // Make sure size is still sane.
+ if .Size in mode_set {
+ api_size, size_err := io.size(stream)
+ expected_api_size := size - 1 if reading_consumes else size
+
+ testing.expectf(t, api_size == expected_api_size,
+ "Read+Size reports %v for its size after Read tests; expected %v", api_size, expected_api_size, loc = loc) or_return
+ testing.expectf(t, size_err == nil,
+ "Read+Size expected no error: %v", size_err, loc = loc) or_return
+ }
+
+ // Read the rest.
+ if size > 1 {
+ bytes_read, err = io.read(stream, read_buf[1:])
+ testing.expectf(t, i64(bytes_read) == size - 1 && err == nil,
+ "Read rest of stream failed: %v != %v, %v", bytes_read, size-1, err, loc = loc) or_return
+ testing.expectf(t, bytes.compare(read_buf, buffer) == 0,
+ "Read buffer compare failed: read_buf<%v> != buffer<%v>", read_buf, buffer, loc = loc) or_return
+ }
+ }
+
+ // Test empty streams and EOF.
+ one_buf: [1]u8
+ bytes_read, err := io.read(stream, one_buf[:])
+ testing.expectf(t, err == .EOF,
+ "Read at end of stream failed: %v, %v", bytes_read, err, loc = loc) or_return
+
+ if !resets_on_empty && .Size in mode_set {
+ // Make sure size is still sane.
+ api_size, size_err := io.size(stream)
+ testing.expectf(t, api_size == size,
+ "Read+Size reports %v for its size after Read tests; expected %v", api_size, size, loc = loc) or_return
+ testing.expectf(t, size_err == nil,
+ "Read+Size expected no error: %v", size_err, loc = loc) or_return
+ }
+
+ passed += { .Read }
+ }
+
+ // Test Write_At.
+ if .Write_At in mode_set {
+ // Test writing from an empty buffer.
+ {
+ nil_slice: []u8
+ bytes_written, err := io.write_at(stream, nil_slice, 0)
+ testing.expectf(t, bytes_written == 0 && err == nil,
+ "Write_At from empty slice failed: bytes_written<%v>, %v", bytes_written, err, loc = loc) or_return
+ }
+
+ // Ensure Write_At does not move the underlying pointer from the start.
+ starting_offset : i64 = -1
+ if .Seek in mode_set {
+ pos, seek_err := io.seek(stream, 0, .Current)
+ testing.expectf(t, pos >= 0 && seek_err == nil,
+ "Write_At+Seek Current failed: %v, %v", pos, seek_err, loc = loc) or_return
+ starting_offset = pos
+ }
+
+ if size > 0 {
+ write_buf, write_buf_alloc_err := make([]u8, size)
+ testing.expectf(t, write_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(write_buf)
+
+ for i in 0..<size {
+ write_buf[i] = buffer[i] ~ 0xAA
+ }
+
+ bytes_written, write_err := io.write_at(stream, write_buf[:], 0)
+ testing.expectf(t, i64(bytes_written) == size && write_err == nil,
+ "Write_At failed: bytes_written<%v> != size<%v>: %v", bytes_written, size, write_err, loc = loc) or_return
+
+ // Test reading what we've written.
+ if .Read_At in mode_set {
+ read_buf, read_buf_alloc_err := make([]u8, size)
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(read_buf)
+ bytes_read, read_err := io.read_at(stream, read_buf[:], 0)
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
+ "Write_At+Read_At failed: bytes_read<%i> != size<%i>, %v", bytes_read, size, read_err, loc = loc) or_return
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
+ "Write_At+Read_At buffer compare failed: write_buf<%v> != read_buf<%v>", write_buf, read_buf, loc = loc) or_return
+ }
+ } else {
+ // Expect that it should be okay to write a single byte to an empty stream.
+ x_buf: [1]u8 = { 'Z' }
+
+ bytes_written, write_err := io.write_at(stream, x_buf[:], 0)
+ testing.expectf(t, i64(bytes_written) == 1 && write_err == nil,
+ "Write_At(0) with 'Z' on empty stream failed: bytes_written<%v>, %v", bytes_written, write_err, loc = loc) or_return
+
+ // Test reading what we've written.
+ if .Read_At in mode_set {
+ x_buf[0] = 0
+ bytes_read, read_err := io.read_at(stream, x_buf[:], 0)
+ testing.expectf(t, i64(bytes_read) == 1 && read_err == nil,
+ "Write_At(0)+Read_At(0) failed expectation: bytes_read<%v> != 1, %q != 'Z', %v", bytes_read, x_buf[0], read_err, loc = loc) or_return
+ }
+ }
+
+ // Ensure Write_At does not move the underlying pointer from the start.
+ if starting_offset != -1 && .Seek in mode_set {
+ pos, seek_err := io.seek(stream, 0, .Current)
+ testing.expectf(t, pos == starting_offset && seek_err == nil,
+ "Write_At+Seek Current isn't %v after writing: %v, %v", starting_offset, pos, seek_err, loc = loc) or_return
+ }
+
+ passed += { .Write_At }
+ }
+
+ // Test Write.
+ if .Write in mode_set {
+ // Test writing from an empty buffer.
+ {
+ nil_slice: []u8
+ bytes_written, err := io.write(stream, nil_slice)
+ testing.expectf(t, bytes_written == 0 && err == nil,
+ "Write from empty slice failed: bytes_written<%v>, %v", bytes_written, err, loc = loc) or_return
+ }
+
+ write_buf, write_buf_alloc_err := make([]u8, size)
+ testing.expectf(t, write_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(write_buf)
+
+ for i in 0..<size {
+ write_buf[i] = buffer[i] ~ 0xAA
+ }
+
+ pos: i64 = -1
+ before_write_size: i64 = -1
+
+ // Do a Seek sanity check after past tests.
+ if .Seek in mode_set {
+ seek_err: io.Error
+ pos, seek_err = io.seek(stream, 0, .Current)
+ testing.expectf(t, seek_err == nil,
+ "Write+Seek(Current) failed: pos<%i>, %v", pos, seek_err) or_return
+ }
+
+ // Get the Size before writing.
+ if .Size in mode_set {
+ size_err: io.Error
+ before_write_size, size_err = io.size(stream)
+ testing.expectf(t, size_err == nil,
+ "Write+Size failed: %v", size_err, loc = loc) or_return
+ }
+
+ bytes_written, write_err := io.write(stream, write_buf[:])
+ testing.expectf(t, i64(bytes_written) == size && write_err == nil,
+ "Write %i bytes failed: %i, %v", size, bytes_written, write_err, loc = loc) or_return
+
+ // Size sanity check, part 2.
+ if before_write_size >= 0 && .Size in mode_set {
+ after_write_size, size_err := io.size(stream)
+ testing.expectf(t, size_err == nil,
+ "Write+Size.part_2 failed: %v", size_err, loc = loc) or_return
+ testing.expectf(t, after_write_size == before_write_size + size,
+ "Write+Size.part_2 failed: %v != %v + %v", after_write_size, before_write_size, size, loc = loc) or_return
+ }
+
+ // Test reading what we've written directly with Read_At.
+ if pos >= 0 && .Read_At in mode_set {
+ read_buf, read_buf_alloc_err := make([]u8, size)
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(read_buf)
+
+ bytes_read, read_err := io.read_at(stream, read_buf[:], pos)
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
+ "Write+Read_At(%i) failed: bytes_read<%i> != size<%i>, %v", pos, bytes_read, size, read_err, loc = loc) or_return
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
+ "Write+Read_At buffer compare failed: read_buf<%v> != write_buf<%v>", read_buf, write_buf, loc = loc) or_return
+ }
+
+ // Test resetting the pointer and reading what we've written with Read.
+ if .Read in mode_set && .Seek in mode_set {
+ seek_err: io.Error
+ pos, seek_err = io.seek(stream, 0, .Start)
+ testing.expectf(t, pos == 0 && seek_err == nil,
+ "Write+Read+Seek(Start) failed: pos<%i>, %v", pos, seek_err) or_return
+
+ read_buf, read_buf_alloc_err := make([]u8, size)
+ testing.expectf(t, read_buf_alloc_err == nil, "allocation failed", loc = loc) or_return
+ defer delete(read_buf)
+
+ bytes_read, read_err := io.read(stream, read_buf[:])
+ testing.expectf(t, i64(bytes_read) == size && read_err == nil,
+ "Write+Read failed: bytes_read<%i> != size<%i>, %v", bytes_read, size, read_err, loc = loc) or_return
+ testing.expectf(t, bytes.compare(read_buf, write_buf) == 0,
+ "Write+Readbuffer compare failed: read_buf<%v> != write_buf<%v>", read_buf, write_buf, loc = loc) or_return
+ }
+
+ passed += { .Write }
+ }
+
+ // Test the other modes.
+ if .Flush in mode_set {
+ err := io.flush(stream)
+ testing.expectf(t, err == nil, "stream failed to Flush: %v", err, loc = loc) or_return
+ passed += { .Flush }
+ }
+
+ if .Close in mode_set {
+ close_err := io.close(stream)
+ testing.expectf(t, close_err == nil, "stream failed to Close: %v", close_err, loc = loc) or_return
+ passed += { .Close }
+ }
+
+ if do_destroy && .Destroy in mode_set {
+ err := io.destroy(stream)
+ testing.expectf(t, err == nil, "stream failed to Destroy: %v", err, loc = loc) or_return
+ passed += { .Destroy }
+ }
+
+ ok = true
+ return
+}
+
+
+
+@test
+test_bytes_reader :: proc(t: ^testing.T) {
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ br: bytes.Reader
+
+ results: Passed_Tests
+ ok: bool
+
+ for end in 0..<i64(len(buf)) {
+ results, ok =_test_stream(t, bytes.reader_init(&br, buf[:end]), buf[:end])
+ if !ok {
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
+ return
+ }
+ }
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_bytes_buffer_stream :: proc(t: ^testing.T) {
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ results: Passed_Tests
+ ok: bool
+
+ for end in 0..<i64(len(buf)) {
+ bb: bytes.Buffer
+ // Mind that `bytes.buffer_init` copies the entire underlying slice.
+ bytes.buffer_init(&bb, buf[:end])
+
+ // `bytes.Buffer` has a behavior of decreasing its size with each read
+ // until it eventually clears the underlying buffer when it runs out of
+ // data to read.
+ results, ok = _test_stream(t, bytes.buffer_to_stream(&bb), buf[:end],
+ reading_consumes = true, resets_on_empty = true)
+ if !ok {
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
+ return
+ }
+ }
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_limited_reader :: proc(t: ^testing.T) {
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ br: bytes.Reader
+ bs := bytes.reader_init(&br, buf[:])
+
+ lr: io.Limited_Reader
+
+ results: Passed_Tests
+ ok: bool
+
+ for end in 0..<i64(len(buf)) {
+ pos, seek_err := io.seek(bs, 0, .Start)
+ if !testing.expectf(t, pos == 0 && seek_err == nil,
+ "Pre-test Seek reset failed: pos<%v>, %v", pos, seek_err) {
+ return
+ }
+
+ results, ok = _test_stream(t, io.limited_reader_init(&lr, bs, end), buf[:end])
+ if !ok {
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
+ return
+ }
+ }
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_section_reader :: proc(t: ^testing.T) {
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ br: bytes.Reader
+ bs := bytes.reader_init(&br, buf[:])
+
+ sr: io.Section_Reader
+
+ results: Passed_Tests
+ ok: bool
+
+ for start in 0..<i64(len(buf)) {
+ for end in start..<i64(len(buf)) {
+ results, ok = _test_stream(t, io.section_reader_init(&sr, bs, start, end-start), buf[start:end])
+ if !ok {
+ log.debugf("buffer[%i:%i] := %v", start, end, buf[start:end])
+ return
+ }
+ }
+ }
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_string_builder_stream :: proc(t: ^testing.T) {
+ sb := strings.builder_make()
+ defer strings.builder_destroy(&sb)
+
+ // String builders do not support reading, so we'll have to set up a few
+ // things outside the main test.
+
+ buf: [32]u8
+ expected_buf: [64]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ expected_buf[i] = 'A' + i
+ strings.write_byte(&sb, 'A' + i)
+ }
+ for i in 32..<u8(len(expected_buf)) {
+ expected_buf[i] = ('A' + i-len(buf)) ~ 0xAA
+ }
+
+ results, _ := _test_stream(t, strings.to_stream(&sb), buf[:],
+ do_destroy = false)
+
+ testing.expectf(t, bytes.compare(sb.buf[:], expected_buf[:]) == 0, "string builder stream failed:\nbuilder<%q>\n!=\nbuffer <%q>", sb.buf[:], expected_buf[:])
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_os_file_stream :: proc(t: ^testing.T) {
+ defer if !testing.failed(t) {
+ testing.expect_value(t, os.remove(TEMPORARY_FILENAME), nil)
+ }
+
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ TEMPORARY_FILENAME :: "test_core_io_os_file_stream"
+
+ fd, open_err := os.open(TEMPORARY_FILENAME, os.O_RDWR | os.O_CREATE | os.O_TRUNC, 0o644)
+ if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) {
+ return
+ }
+
+ stream := os.stream_from_handle(fd)
+
+ bytes_written, write_err := io.write(stream, buf[:])
+ if !testing.expectf(t, bytes_written == len(buf) && write_err == nil,
+ "failed to Write initial buffer: bytes_written<%v> != len_buf<%v>, %v", bytes_written, len(buf), write_err) {
+ return
+ }
+
+ flush_err := io.flush(stream)
+ if !testing.expectf(t, flush_err == nil,
+ "failed to Flush initial buffer: %v", write_err) {
+ return
+ }
+
+ results, _ := _test_stream(t, stream, buf[:])
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_os2_file_stream :: proc(t: ^testing.T) {
+ defer if !testing.failed(t) {
+ testing.expect_value(t, os2.remove(TEMPORARY_FILENAME), nil)
+ }
+
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ TEMPORARY_FILENAME :: "test_core_io_os2_file_stream"
+
+ fd, open_err := os2.open(TEMPORARY_FILENAME, {.Read, .Write, .Create, .Trunc})
+ if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) {
+ return
+ }
+
+ stream := os2.to_stream(fd)
+
+ bytes_written, write_err := io.write(stream, buf[:])
+ if !testing.expectf(t, bytes_written == len(buf) && write_err == nil,
+ "failed to Write initial buffer: bytes_written<%v> != len_buf<%v>, %v", bytes_written, len(buf), write_err) {
+ return
+ }
+
+ flush_err := io.flush(stream)
+ if !testing.expectf(t, flush_err == nil,
+ "failed to Flush initial buffer: %v", write_err) {
+ return
+ }
+
+ // os2 file stream proc close and destroy are the same.
+ results, _ := _test_stream(t, stream, buf[:], do_destroy = false)
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_bufio_buffered_writer :: proc(t: ^testing.T) {
+ // Using a strings.Builder as the backing stream.
+
+ sb := strings.builder_make()
+ defer strings.builder_destroy(&sb)
+
+ buf: [32]u8
+ expected_buf: [64]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ expected_buf[i] = 'A' + i
+ strings.write_byte(&sb, 'A' + i)
+ }
+ for i in 32..<u8(len(expected_buf)) {
+ expected_buf[i] = ('A' + i-len(buf)) ~ 0xAA
+ }
+
+ writer: bufio.Writer
+ bufio.writer_init(&writer, strings.to_stream(&sb))
+ defer bufio.writer_destroy(&writer)
+
+ results, _ := _test_stream(t, bufio.writer_to_stream(&writer), buf[:],
+ do_destroy = false)
+
+ testing.expectf(t, bytes.compare(sb.buf[:], expected_buf[:]) == 0, "bufio buffered string builder stream failed:\nbuilder<%q>\n!=\nbuffer <%q>", sb.buf[:], expected_buf[:])
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_bufio_buffered_reader :: proc(t: ^testing.T) {
+ // Using a bytes.Reader as the backing stream.
+
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ results: Passed_Tests
+ ok: bool
+
+ for end in 0..<i64(len(buf)) {
+ br: bytes.Reader
+ bs := bytes.reader_init(&br, buf[:end])
+
+ reader: bufio.Reader
+ bufio.reader_init(&reader, bs)
+ defer bufio.reader_destroy(&reader)
+
+ results, ok = _test_stream(t, bufio.reader_to_stream(&reader), buf[:end])
+ if !ok {
+ log.debugf("buffer[:%i] := %v", end, buf[:end])
+ return
+ }
+ }
+
+ log.debugf("%#v", results)
+}
+
+@test
+test_bufio_buffered_read_writer :: proc(t: ^testing.T) {
+ // Using an os2.File as the backing stream for both reader & writer.
+
+ defer if !testing.failed(t) {
+ testing.expect_value(t, os2.remove(TEMPORARY_FILENAME), nil)
+ }
+
+ buf: [32]u8
+ for i in 0..<u8(len(buf)) {
+ buf[i] = 'A' + i
+ }
+
+ TEMPORARY_FILENAME :: "test_core_io_bufio_read_writer_os2_file_stream"
+
+ fd, open_err := os2.open(TEMPORARY_FILENAME, {.Read, .Write, .Create, .Trunc})
+ if !testing.expectf(t, open_err == nil, "error on opening %q: %v", TEMPORARY_FILENAME, open_err) {
+ return
+ }
+ defer testing.expect_value(t, os2.close(fd), nil)
+
+ stream := os2.to_stream(fd)
+
+ bytes_written, write_err := io.write(stream, buf[:])
+ if !testing.expectf(t, bytes_written == len(buf) && write_err == nil,
+ "failed to Write initial buffer: bytes_written<%v> != len_buf<%v>, %v", bytes_written, len(buf), write_err) {
+ return
+ }
+
+ flush_err := io.flush(stream)
+ if !testing.expectf(t, flush_err == nil,
+ "failed to Flush initial buffer: %v", write_err) {
+ return
+ }
+
+ // bufio.Read_Writer isn't capable of seeking, so we have to reset the os2
+ // stream back to the start here.
+ pos, seek_err := io.seek(stream, 0, .Start)
+ if !testing.expectf(t, pos == 0 && seek_err == nil,
+ "Pre-test Seek reset failed: pos<%v>, %v", pos, seek_err) {
+ return
+ }
+
+ reader: bufio.Reader
+ writer: bufio.Writer
+ read_writer: bufio.Read_Writer
+
+ bufio.reader_init(&reader, stream)
+ defer bufio.reader_destroy(&reader)
+ bufio.writer_init(&writer, stream)
+ defer bufio.writer_destroy(&writer)
+
+ bufio.read_writer_init(&read_writer, &reader, &writer)
+
+ // os2 file stream proc close and destroy are the same.
+ results, _ := _test_stream(t, bufio.read_writer_to_stream(&read_writer), buf[:], do_destroy = false)
+
+ log.debugf("%#v", results)
+}
diff --git a/tests/core/mem/test_mem_dynamic_pool.odin b/tests/core/mem/test_mem_dynamic_pool.odin
index d1086cfe6..fa204d3b1 100644
--- a/tests/core/mem/test_mem_dynamic_pool.odin
+++ b/tests/core/mem/test_mem_dynamic_pool.odin
@@ -6,7 +6,7 @@ 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)
+ mem.dynamic_pool_init(&pool, alignment = alignment)
pool_allocator := mem.dynamic_pool_allocator(&pool)
element, err := mem.alloc(num_bytes, alignment, pool_allocator)
@@ -48,7 +48,7 @@ expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, out_band_si
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)
+ mem.dynamic_pool_init(&pool, out_band_size = out_band_size)
pool_allocator := mem.dynamic_pool_allocator(&pool)
element, err := mem.alloc(num_bytes, allocator = pool_allocator)
diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin
index f38fa11e6..bc3ff5c46 100644
--- a/tests/core/net/test_core_net.odin
+++ b/tests/core/net/test_core_net.odin
@@ -10,7 +10,8 @@
A test suite for `core:net`
*/
-//+build !netbsd !openbsd
+#+build !netbsd
+#+build !openbsd
package test_core_net
import "core:testing"
@@ -216,39 +217,31 @@ IP_Address_Parsing_Test_Vectors :: []IP_Address_Parsing_Test_Vector{
{ .IP6, "c0a8", "", ""},
}
-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) {
- skt1, err1 := net.listen_tcp(ENDPOINT_TWO_SERVERS)
+ skt1, err1 := net.listen_tcp({address=net.IP4_Address{127, 0, 0, 1}, port=0})
defer net.close(skt1)
- skt2, err2 := net.listen_tcp(ENDPOINT_TWO_SERVERS)
+
+ ep, perr := net.bound_endpoint(skt1)
+
+ skt2, err2 := net.listen_tcp(ep)
defer net.close(skt2)
testing.expect(t, err1 == nil, "expected first server binding to endpoint to do so without error")
+ testing.expect_value(t, perr, nil)
testing.expect(t, err2 == net.Bind_Error.Address_In_Use, "expected second server to bind to an endpoint to return .Address_In_Use")
}
@(test)
-client_connects_to_closed_port :: proc(t: ^testing.T) {
-
- skt, err := net.dial_tcp(ENDPOINT_CLOSED_PORT)
- defer net.close(skt)
- testing.expect(t, err == net.Dial_Error.Refused, "expected dial of a closed endpoint to return .Refused")
-}
-
-
-@(test)
client_sends_server_data :: proc(t: ^testing.T) {
CONTENT: string: "Hellope!"
SEND_TIMEOUT :: time.Duration(1 * time.Second)
RECV_TIMEOUT :: time.Duration(1 * time.Second)
+ @static endpoint: net.Endpoint
+ endpoint.address = net.IP4_Address{127, 0, 0, 1}
+
Thread_Data :: struct {
t: ^testing.T,
skt: net.Any_Socket,
@@ -265,7 +258,7 @@ client_sends_server_data :: proc(t: ^testing.T) {
defer sync.wait_group_done(r.wg)
- if r.skt, r.err = net.dial_tcp(ENDPOINT_SERVER_SENDS); r.err != nil {
+ if r.skt, r.err = net.dial_tcp(endpoint); r.err != nil {
testing.expectf(r.t, false, "[tcp_client:dial_tcp] %v", r.err)
return
}
@@ -280,12 +273,17 @@ client_sends_server_data :: proc(t: ^testing.T) {
defer sync.wait_group_done(r.wg)
- if r.skt, r.err = net.listen_tcp(ENDPOINT_SERVER_SENDS); r.err != nil {
+ if r.skt, r.err = net.listen_tcp(endpoint); r.err != nil {
sync.wait_group_done(r.wg)
testing.expectf(r.t, false, "[tcp_server:listen_tcp] %v", r.err)
return
}
+ endpoint, r.err = net.bound_endpoint(r.skt.(net.TCP_Socket))
+ if !testing.expect_value(r.t, r.err, nil) {
+ return
+ }
+
sync.wait_group_done(r.wg)
client: net.TCP_Socket
@@ -523,17 +521,25 @@ join_url_test :: proc(t: ^testing.T) {
@test
test_udp_echo :: proc(t: ^testing.T) {
+ endpoint := net.Endpoint{address=net.IP4_Address{127, 0, 0, 1}, port=0}
+
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)
+ bind_server_err := net.bind(server, endpoint)
if !testing.expect_value(t, bind_server_err, nil) {
return
}
+ perr: net.Network_Error
+ endpoint, perr = net.bound_endpoint(server)
+ if !testing.expect_value(t, perr, nil) {
+ return
+ }
+
client, make_client_err := net.make_unbound_udp_socket(.IP4)
if !testing.expect_value(t, make_client_err, nil) {
return
@@ -543,7 +549,7 @@ test_udp_echo :: proc(t: ^testing.T) {
msg := "Hellope world!"
buf: [64]u8
- bytes_written, send_err := net.send_udp(client, transmute([]u8)msg[:], ENDPOINT_UDP_ECHO)
+ bytes_written, send_err := net.send_udp(client, transmute([]u8)msg[:], endpoint)
if !testing.expect_value(t, send_err, nil) {
return
}
@@ -599,7 +605,7 @@ test_dns_resolve :: proc(t: ^testing.T) {
@test
test_nonblocking_option :: proc(t: ^testing.T) {
- server, listen_err := net.listen_tcp(ENDPOINT_NONBLOCK)
+ server, listen_err := net.listen_tcp({address=net.IP4_Address{127, 0, 0, 1}, port=0})
if !testing.expect_value(t, listen_err, nil) {
return
}
diff --git a/tests/core/net/test_core_net_freebsd.odin b/tests/core/net/test_core_net_freebsd.odin
index 61e801f2b..39e364e80 100644
--- a/tests/core/net/test_core_net_freebsd.odin
+++ b/tests/core/net/test_core_net_freebsd.odin
@@ -10,7 +10,7 @@
A test suite for `core:net`
*/
-//+build freebsd
+#+build freebsd
package test_core_net
import "core:net"
diff --git a/tests/core/normal.odin b/tests/core/normal.odin
index 510d66d1a..0670842ac 100644
--- a/tests/core/normal.odin
+++ b/tests/core/normal.odin
@@ -23,6 +23,7 @@ download_assets :: proc() {
@(require) import "encoding/xml"
@(require) import "flags"
@(require) import "fmt"
+@(require) import "io"
@(require) import "math"
@(require) import "math/big"
@(require) import "math/linalg/glsl"
@@ -38,6 +39,8 @@ download_assets :: proc() {
@(require) import "slice"
@(require) import "strconv"
@(require) import "strings"
+@(require) import "sync"
+@(require) import "sync/chan"
@(require) import "sys/posix"
@(require) import "sys/windows"
@(require) import "text/i18n"
diff --git a/tests/core/odin/test_file_tags.odin b/tests/core/odin/test_file_tags.odin
new file mode 100644
index 000000000..dc004dfe3
--- /dev/null
+++ b/tests/core/odin/test_file_tags.odin
@@ -0,0 +1,155 @@
+package test_core_odin_parser
+
+import "base:runtime"
+import "core:testing"
+import "core:slice"
+import "core:odin/ast"
+import "core:odin/parser"
+
+@test
+test_parse_file_tags :: proc(t: ^testing.T) {
+ context.allocator = context.temp_allocator
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+
+ Test_Case :: struct {
+ src: string,
+ tags: parser.File_Tags,
+ matching_targets: []struct{
+ target: parser.Build_Target,
+ result: bool,
+ },
+ }
+
+ test_cases := []Test_Case{
+ {// [0]
+ src = ``,
+ tags = {},
+ }, {// [1]
+ src = `
+package main
+ `,
+ tags = {},
+ matching_targets = {
+ {{.Windows, .amd64, "foo"}, true},
+ },
+ }, {// [2]
+ src = `
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+build arm32, arm64
+package main
+ `,
+ tags = {
+ build = {
+ {os = {.Linux}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = {.Darwin}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = {.FreeBSD}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = {.OpenBSD}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = {.NetBSD}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = {.Haiku}, arch = runtime.ALL_ODIN_ARCH_TYPES},
+ {os = runtime.ALL_ODIN_OS_TYPES, arch = {.arm32}},
+ {os = runtime.ALL_ODIN_OS_TYPES, arch = {.arm64}},
+ },
+ },
+ matching_targets = {
+ {{.Linux, .amd64, "foo"}, true},
+ {{.Windows, .arm64, "foo"}, true},
+ {{.Windows, .amd64, "foo"}, false},
+ },
+ }, {// [3]
+ src = `
+#+private
+#+lazy
+#+no-instrumentation
+#+ignore
+// some other comment
+package main
+ `,
+ tags = {
+ private = .Package,
+ no_instrumentation = true,
+ lazy = true,
+ ignore = true,
+ },
+ matching_targets = {
+ {{.Linux, .amd64, "foo"}, false},
+ },
+ }, {// [4]
+ src = `
+#+build-project-name foo !bar, baz
+#+build js wasm32, js wasm64p32
+package main
+ `,
+ tags = {
+ build_project_name = {{"foo", "!bar"}, {"baz"}},
+ build = {
+ {
+ os = {.JS},
+ arch = {.wasm32},
+ }, {
+ os = {.JS},
+ arch = {.wasm64p32},
+ },
+ },
+ },
+ matching_targets = {
+ {{.JS, .wasm32, "foo"}, true},
+ {{.JS, .wasm64p32, "baz"}, true},
+ {{.JS, .wasm64p32, "bar"}, false},
+ },
+ },
+ }
+
+ for test_case, test_case_i in test_cases {
+
+ file := ast.File{
+ fullpath = "test.odin",
+ src = test_case.src,
+ }
+
+ p := parser.default_parser()
+ ok := parser.parse_file(&p, &file)
+
+ testing.expect(t, ok, "bad parse")
+
+ tags := parser.parse_file_tags(file)
+
+
+ build_project_name_the_same: bool
+ check: if len(test_case.tags.build_project_name) == len(tags.build_project_name) {
+ for tag, i in test_case.tags.build_project_name {
+ slice.equal(tag, tags.build_project_name[i]) or_break check
+ }
+ build_project_name_the_same = true
+ }
+ testing.expectf(t, build_project_name_the_same,
+ "[%d] file_tags.build_project_name expected:\n%#v, got:\n%#v",
+ test_case_i, test_case.tags.build_project_name, tags.build_project_name)
+
+ testing.expectf(t, slice.equal(test_case.tags.build, tags.build),
+ "[%d] file_tags.build expected:\n%#v, got:\n%#v",
+ test_case_i, test_case.tags.build, tags.build)
+
+ testing.expectf(t, test_case.tags.private == tags.private,
+ "[%d] file_tags.private expected:\n%v, got:\n%v",
+ test_case_i, test_case.tags.private, tags.private)
+
+ testing.expectf(t, test_case.tags.ignore == tags.ignore,
+ "[%d] file_tags.ignore expected:\n%v, got:\n%v",
+ test_case_i, test_case.tags.ignore, tags.ignore)
+
+ testing.expectf(t, test_case.tags.lazy == tags.lazy,
+ "[%d] file_tags.lazy expected:\n%v, got:\n%v",
+ test_case_i, test_case.tags.lazy, tags.lazy)
+
+ testing.expectf(t, test_case.tags.no_instrumentation == tags.no_instrumentation,
+ "[%d] file_tags.no_instrumentation expected:\n%v, got:\n%v",
+ test_case_i, test_case.tags.no_instrumentation, tags.no_instrumentation)
+
+ for target in test_case.matching_targets {
+ matches := parser.match_build_tags(test_case.tags, target.target)
+ testing.expectf(t, matches == target.result,
+ "[%d] Expected parser.match_build_tags(%#v) == %v, got %v",
+ test_case_i, target.target, target.result, matches)
+ }
+ }
+}
diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin
index 008146dcf..f39caff48 100644
--- a/tests/core/runtime/test_core_runtime.odin
+++ b/tests/core/runtime/test_core_runtime.odin
@@ -11,6 +11,7 @@ import "core:testing"
test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) {
arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena)
+ defer runtime.arena_destroy(&arena)
_, _ = mem.alloc(int(runtime.DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE)-120)
_, err := mem.alloc(112, 32)
@@ -22,6 +23,7 @@ test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) {
test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena)
+ defer runtime.arena_destroy(&arena)
mappy: map[[8]int]int
err := reserve(&mappy, 50000)
@@ -32,6 +34,7 @@ test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) {
arena: runtime.Arena
context.allocator = runtime.arena_allocator(&arena)
+ defer runtime.arena_destroy(&arena)
bytes, err := mem.alloc_bytes(10, 16)
testing.expect(t, err == nil)
diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin
index 3e249055b..16d5b23a4 100644
--- a/tests/core/slice/test_core_slice.odin
+++ b/tests/core/slice/test_core_slice.odin
@@ -275,4 +275,34 @@ test_unique :: proc(t: ^testing.T) {
delete(original)
delete(expected)
}
-} \ No newline at end of file
+}
+
+@test
+test_compare_empty :: proc(t: ^testing.T) {
+ a := []int{}
+ b := []int{}
+ c: [dynamic]int = { 0 }
+ d: [dynamic]int = { 1 }
+ clear(&c)
+ clear(&d)
+ defer {
+ delete(c)
+ delete(d)
+ }
+
+ testing.expectf(t, len(a) == 0,
+ "Expected length of slice `a` to be zero")
+ testing.expectf(t, len(c) == 0,
+ "Expected length of dynamic array `c` to be zero")
+ testing.expectf(t, len(d) == 0,
+ "Expected length of dynamic array `d` to be zero")
+
+ testing.expectf(t, slice.equal(a, a),
+ "Expected empty slice to be equal to itself")
+ testing.expectf(t, slice.equal(a, b),
+ "Expected two different but empty stack-based slices to be equivalent")
+ testing.expectf(t, slice.equal(a, c[:]),
+ "Expected empty slice to be equal to slice of empty dynamic array")
+ testing.expectf(t, slice.equal(c[:], d[:]),
+ "Expected two separate empty slices of two dynamic arrays to be equal")
+}
diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin
index 0ee2b3eb9..0d94b9c62 100644
--- a/tests/core/strings/test_core_strings.odin
+++ b/tests/core/strings/test_core_strings.odin
@@ -48,18 +48,19 @@ Cut_Test :: struct {
}
cut_tests :: []Cut_Test{
- {"some example text", 0, 4, "some" },
- {"some example text", 2, 2, "me" },
- {"some example text", 5, 7, "example" },
- {"some example text", 5, 0, "example text"},
- {"恥ずべきフクロウ", 4, 0, "フクロウ" },
+ {"some example text", 0, 0, "some example text" },
+ {"some example text", 0, 4, "some" },
+ {"some example text", 2, 2, "me" },
+ {"some example text", 5, 7, "example" },
+ {"some example text", 5, 0, "example text" },
+ {"恥ずべきフクロウ", 0, 0, "恥ずべきフクロウ" },
+ {"恥ずべきフクロウ", 4, 0, "フクロウ" },
}
@test
test_cut :: proc(t: ^testing.T) {
for test in cut_tests {
res := strings.cut(test.input, test.offset, test.length)
- defer delete(res)
testing.expectf(
t,
@@ -123,4 +124,35 @@ test_case_conversion :: proc(t: ^testing.T) {
testing.expectf(t, result == entry.s, "ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result)
}
}
-} \ No newline at end of file
+}
+
+@(test)
+test_substring :: proc(t: ^testing.T) {
+ Case :: struct {
+ s: string,
+ start: int,
+ end: int,
+ sub: string,
+ ok: bool,
+ }
+ cases := []Case {
+ {ok = true},
+ {s = "", start = -1, ok = false},
+ {s = "", end = -1, ok = false},
+ {s = "", end = +1, ok = false},
+ {s = "Hello", end = len("Hello"), sub = "Hello", ok = true},
+ {s = "Hello", start = 1, end = len("Hello"), sub = "ello", ok = true},
+ {s = "Hello", start = 1, end = len("Hello") - 1, sub = "ell", ok = true},
+ {s = "Hello", end = len("Hello") + 1, sub = "Hello", ok = false},
+ {s = "小猫咪", start = 0, end = 3, sub = "小猫咪", ok = true},
+ {s = "小猫咪", start = 1, end = 3, sub = "猫咪", ok = true},
+ {s = "小猫咪", start = 1, end = 5, sub = "猫咪", ok = false},
+ {s = "小猫咪", start = 1, end = 1, sub = "", ok = true},
+ }
+
+ for tc in cases {
+ sub, ok := strings.substring(tc.s, tc.start, tc.end)
+ testing.expectf(t, ok == tc.ok, "expected %v[%v:%v] to return ok: %v", tc.s, tc.start, tc.end, tc.ok)
+ testing.expectf(t, sub == tc.sub, "expected %v[%v:%v] to return sub: %v, got: %v", tc.s, tc.start, tc.end, tc.sub, sub)
+ }
+}
diff --git a/tests/core/sync/chan/test_core_sync_chan.odin b/tests/core/sync/chan/test_core_sync_chan.odin
new file mode 100644
index 000000000..9b8d9b354
--- /dev/null
+++ b/tests/core/sync/chan/test_core_sync_chan.odin
@@ -0,0 +1,274 @@
+package test_core_sync_chan
+
+import "base:runtime"
+import "base:intrinsics"
+import "core:log"
+import "core:math/rand"
+import "core:sync/chan"
+import "core:testing"
+import "core:thread"
+import "core:time"
+
+
+Message_Type :: enum i32 {
+ Result,
+ Add,
+ Multiply,
+ Subtract,
+ Divide,
+ End,
+}
+
+Message :: struct {
+ type: Message_Type,
+ i: i64,
+}
+
+Comm :: struct {
+ host: chan.Chan(Message),
+ client: chan.Chan(Message),
+ manual_buffering: bool,
+}
+
+BUFFER_SIZE :: 8
+MAX_RAND :: 32
+FAIL_TIME :: 1 * time.Second
+SLEEP_TIME :: 1 * time.Millisecond
+
+comm_client :: proc(th: ^thread.Thread) {
+ data := cast(^Comm)th.data
+ manual_buffering := data.manual_buffering
+
+ n: i64
+
+ for manual_buffering && !chan.can_recv(data.host) {
+ thread.yield()
+ }
+
+ recv_loop: for msg in chan.recv(data.host) {
+ #partial switch msg.type {
+ case .Add: n += msg.i
+ case .Multiply: n *= msg.i
+ case .Subtract: n -= msg.i
+ case .Divide: n /= msg.i
+ case .End:
+ break recv_loop
+ case:
+ panic("Unknown message type for client.")
+ }
+
+ for manual_buffering && !chan.can_recv(data.host) {
+ thread.yield()
+ }
+ }
+
+ for manual_buffering && !chan.can_send(data.host) {
+ thread.yield()
+ }
+
+ chan.send(data.client, Message{.Result, n})
+ chan.close(data.client)
+}
+
+send_messages :: proc(t: ^testing.T, host: chan.Chan(Message), manual_buffering: bool = false) -> (expected: i64) {
+ expected = 1
+ for manual_buffering && !chan.can_send(host) {
+ thread.yield()
+ }
+ chan.send(host, Message{.Add, 1})
+ log.debug(Message{.Add, 1})
+
+ for _ in 0..<1+2*BUFFER_SIZE {
+ msg: Message
+ msg.i = 1 + rand.int63_max(MAX_RAND)
+ switch rand.int_max(4) {
+ case 0:
+ msg.type = .Add
+ expected += msg.i
+ case 1:
+ msg.type = .Multiply
+ expected *= msg.i
+ case 2:
+ msg.type = .Subtract
+ expected -= msg.i
+ case 3:
+ msg.type = .Divide
+ expected /= msg.i
+ }
+
+ for manual_buffering && !chan.can_send(host) {
+ thread.yield()
+ }
+ if manual_buffering {
+ testing.expect(t, chan.len(host) == 0)
+ }
+
+ chan.send(host, msg)
+ log.debug(msg)
+ }
+
+ for manual_buffering && !chan.can_send(host) {
+ thread.yield()
+ }
+ chan.send(host, Message{.End, 0})
+ log.debug(Message{.End, 0})
+ chan.close(host)
+
+ return
+}
+
+@test
+test_chan_buffered :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ comm: Comm
+ alloc_err: runtime.Allocator_Error
+ comm.host, alloc_err = chan.create_buffered(chan.Chan(Message), BUFFER_SIZE, context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ comm.client, alloc_err = chan.create_buffered(chan.Chan(Message), BUFFER_SIZE, context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ defer {
+ chan.destroy(comm.host)
+ chan.destroy(comm.client)
+ }
+
+ testing.expect(t, chan.is_buffered(comm.host))
+ testing.expect(t, chan.is_buffered(comm.client))
+ testing.expect(t, !chan.is_unbuffered(comm.host))
+ testing.expect(t, !chan.is_unbuffered(comm.client))
+ testing.expect_value(t, chan.len(comm.host), 0)
+ testing.expect_value(t, chan.len(comm.client), 0)
+ testing.expect_value(t, chan.cap(comm.host), BUFFER_SIZE)
+ testing.expect_value(t, chan.cap(comm.client), BUFFER_SIZE)
+
+ reckoner := thread.create(comm_client)
+ defer thread.destroy(reckoner)
+ reckoner.data = &comm
+ thread.start(reckoner)
+
+ expected := send_messages(t, comm.host, manual_buffering = false)
+
+ // Sleep so we can give the other thread enough time to buffer its message.
+ time.sleep(SLEEP_TIME)
+
+ testing.expect_value(t, chan.len(comm.client), 1)
+ result, ok := chan.try_recv(comm.client)
+
+ // One more sleep to ensure it has enough time to close.
+ time.sleep(SLEEP_TIME)
+
+ testing.expect_value(t, chan.is_closed(comm.client), true)
+ testing.expect_value(t, ok, true)
+ testing.expect_value(t, result.i, expected)
+ log.debug(result, expected)
+
+ // Make sure sending to closed channels fails.
+ testing.expect_value(t, chan.send(comm.host, Message{.End, 0}), false)
+ testing.expect_value(t, chan.send(comm.client, Message{.End, 0}), false)
+ testing.expect_value(t, chan.try_send(comm.host, Message{.End, 0}), false)
+ testing.expect_value(t, chan.try_send(comm.client, Message{.End, 0}), false)
+ _, ok = chan.recv(comm.host); testing.expect_value(t, ok, false)
+ _, ok = chan.recv(comm.client); testing.expect_value(t, ok, false)
+ _, ok = chan.try_recv(comm.host); testing.expect_value(t, ok, false)
+ _, ok = chan.try_recv(comm.client); testing.expect_value(t, ok, false)
+}
+
+@test
+test_chan_unbuffered :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ comm: Comm
+ comm.manual_buffering = true
+ alloc_err: runtime.Allocator_Error
+ comm.host, alloc_err = chan.create_unbuffered(chan.Chan(Message), context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ comm.client, alloc_err = chan.create_unbuffered(chan.Chan(Message), context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ defer {
+ chan.destroy(comm.host)
+ chan.destroy(comm.client)
+ }
+
+ testing.expect(t, !chan.is_buffered(comm.host))
+ testing.expect(t, !chan.is_buffered(comm.client))
+ testing.expect(t, chan.is_unbuffered(comm.host))
+ testing.expect(t, chan.is_unbuffered(comm.client))
+ testing.expect_value(t, chan.len(comm.host), 0)
+ testing.expect_value(t, chan.len(comm.client), 0)
+ testing.expect_value(t, chan.cap(comm.host), 0)
+ testing.expect_value(t, chan.cap(comm.client), 0)
+
+ reckoner := thread.create(comm_client)
+ defer thread.destroy(reckoner)
+ reckoner.data = &comm
+ thread.start(reckoner)
+
+ for !chan.can_send(comm.client) {
+ thread.yield()
+ }
+
+ expected := send_messages(t, comm.host)
+ testing.expect_value(t, chan.is_closed(comm.host), true)
+
+ for !chan.can_recv(comm.client) {
+ thread.yield()
+ }
+
+ result, ok := chan.try_recv(comm.client)
+ testing.expect_value(t, ok, true)
+ testing.expect_value(t, result.i, expected)
+ log.debug(result, expected)
+
+ // Sleep so we can give the other thread enough time to close its side
+ // after we've received its message.
+ time.sleep(SLEEP_TIME)
+
+ testing.expect_value(t, chan.is_closed(comm.client), true)
+
+ // Make sure sending and receiving on closed channels fails.
+ testing.expect_value(t, chan.send(comm.host, Message{.End, 0}), false)
+ testing.expect_value(t, chan.send(comm.client, Message{.End, 0}), false)
+ testing.expect_value(t, chan.try_send(comm.host, Message{.End, 0}), false)
+ testing.expect_value(t, chan.try_send(comm.client, Message{.End, 0}), false)
+ _, ok = chan.recv(comm.host); testing.expect_value(t, ok, false)
+ _, ok = chan.recv(comm.client); testing.expect_value(t, ok, false)
+ _, ok = chan.try_recv(comm.host); testing.expect_value(t, ok, false)
+ _, ok = chan.try_recv(comm.client); testing.expect_value(t, ok, false)
+}
+
+@test
+test_full_buffered_closed_chan_deadlock :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ ch, alloc_err := chan.create_buffered(chan.Chan(int), 1, context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ defer chan.destroy(ch)
+
+ testing.expect(t, chan.can_send(ch))
+ testing.expect(t, chan.send(ch, 32))
+ testing.expect(t, chan.close(ch))
+ testing.expect(t, !chan.send(ch, 32))
+}
+
+// This test guarantees a buffered channel's messages can still be received
+// even after closing. This is currently how the API works. If that changes,
+// this test will need to change.
+@test
+test_accept_message_from_closed_buffered_chan :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ ch, alloc_err := chan.create_buffered(chan.Chan(int), 2, context.allocator)
+ assert(alloc_err == nil, "allocation failed")
+ defer chan.destroy(ch)
+
+ testing.expect(t, chan.can_send(ch))
+ testing.expect(t, chan.send(ch, 32))
+ testing.expect(t, chan.send(ch, 64))
+ testing.expect(t, chan.close(ch))
+ result, ok := chan.recv(ch)
+ testing.expect_value(t, result, 32)
+ testing.expect(t, ok)
+ result, ok = chan.try_recv(ch)
+ testing.expect_value(t, result, 64)
+ testing.expect(t, ok)
+}
diff --git a/tests/core/sync/test_core_sync.odin b/tests/core/sync/test_core_sync.odin
new file mode 100644
index 000000000..d6a7a9517
--- /dev/null
+++ b/tests/core/sync/test_core_sync.odin
@@ -0,0 +1,714 @@
+// NOTE(Feoramund): These tests should be run a few hundred times, with and
+// without `-sanitize:thread` enabled, to ensure maximum safety.
+//
+// Keep in mind that running with the debug logs uncommented can result in
+// failures disappearing due to the delay of sending the log message causing
+// different synchronization patterns.
+
+package test_core_sync
+
+import "base:intrinsics"
+// import "core:log"
+import "core:sync"
+import "core:testing"
+import "core:thread"
+import "core:time"
+
+FAIL_TIME :: 1 * time.Second
+SLEEP_TIME :: 1 * time.Millisecond
+SMALL_SLEEP_TIME :: 10 * time.Microsecond
+
+// This needs to be high enough to cause a data race if any of the
+// synchronization primitives fail.
+THREADS :: 8
+
+// Manually wait on all threads to finish.
+//
+// This reduces a dependency on a `Wait_Group` or similar primitives.
+//
+// It's also important that we wait for every thread to finish, as it's
+// possible for a thread to finish after the test if we don't check, despite
+// joining it to the test thread.
+wait_for :: proc(threads: []^thread.Thread) {
+ wait_loop: for {
+ count := len(threads)
+ for v in threads {
+ if thread.is_done(v) {
+ count -= 1
+ }
+ }
+ if count == 0 {
+ break wait_loop
+ }
+ thread.yield()
+ }
+ for t in threads {
+ thread.join(t)
+ thread.destroy(t)
+ }
+}
+
+//
+// core:sync/primitives.odin
+//
+
+@test
+test_mutex :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ m: sync.Mutex,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("MUTEX-%v> locking", th.id)
+ sync.mutex_lock(&data.m)
+ data.number += 1
+ // log.debugf("MUTEX-%v> unlocking", th.id)
+ sync.mutex_unlock(&data.m)
+ // log.debugf("MUTEX-%v> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_rw_mutex :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ m1: sync.RW_Mutex,
+ m2: sync.RW_Mutex,
+ number1: int,
+ number2: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ sync.rw_mutex_shared_lock(&data.m1)
+ n := data.number1
+ sync.rw_mutex_shared_unlock(&data.m1)
+
+ sync.rw_mutex_lock(&data.m2)
+ data.number2 += n
+ sync.rw_mutex_unlock(&data.m2)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ sync.rw_mutex_lock(&data.m1)
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ data.number1 = 1
+ sync.rw_mutex_unlock(&data.m1)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number2, THREADS)
+}
+
+@test
+test_recursive_mutex :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ m: sync.Recursive_Mutex,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("REC_MUTEX-%v> locking", th.id)
+ tried1 := sync.recursive_mutex_try_lock(&data.m)
+ for _ in 0..<3 {
+ sync.recursive_mutex_lock(&data.m)
+ }
+ tried2 := sync.recursive_mutex_try_lock(&data.m)
+ // log.debugf("REC_MUTEX-%v> locked", th.id)
+ data.number += 1
+ // log.debugf("REC_MUTEX-%v> unlocking", th.id)
+ for _ in 0..<3 {
+ sync.recursive_mutex_unlock(&data.m)
+ }
+ if tried1 { sync.recursive_mutex_unlock(&data.m) }
+ if tried2 { sync.recursive_mutex_unlock(&data.m) }
+ // log.debugf("REC_MUTEX-%v> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_cond :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ c: sync.Cond,
+ m: sync.Mutex,
+ i: int,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ sync.mutex_lock(&data.m)
+
+ for intrinsics.atomic_load(&data.i) != 1 {
+ sync.cond_wait(&data.c, &data.m)
+ }
+
+ data.number += intrinsics.atomic_load(&data.i)
+
+ sync.mutex_unlock(&data.m)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+ data.i = -1
+
+ sync.mutex_lock(&data.m)
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ time.sleep(SLEEP_TIME)
+ data.i = 1
+ sync.mutex_unlock(&data.m)
+ sync.cond_broadcast(&data.c)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_cond_with_timeout :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ c: sync.Cond
+ m: sync.Mutex
+ sync.mutex_lock(&m)
+ sync.cond_wait_with_timeout(&c, &m, SLEEP_TIME)
+}
+
+@test
+test_semaphore :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ s: sync.Sema,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("SEM-%v> waiting", th.id)
+ sync.sema_wait(&data.s)
+ data.number += 1
+ // log.debugf("SEM-%v> posting", th.id)
+ sync.sema_post(&data.s)
+ // log.debugf("SEM-%v> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+ sync.sema_post(&data.s)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_semaphore_with_timeout :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ s: sync.Sema
+ sync.sema_wait_with_timeout(&s, SLEEP_TIME)
+}
+
+@test
+test_futex :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ f: sync.Futex,
+ i: int,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("FUTEX-%v> waiting", th.id)
+ sync.futex_wait(&data.f, 3)
+ // log.debugf("FUTEX-%v> done", th.id)
+
+ n := data.i
+ intrinsics.atomic_add(&data.number, n)
+ }
+
+ data: Data
+ data.i = -1
+ data.f = 3
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ data.i = 1
+ // Change the futex variable to keep late-starters from stalling.
+ data.f = 0
+ sync.futex_broadcast(&data.f)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_futex_with_timeout :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ f: sync.Futex = 1
+ sync.futex_wait_with_timeout(&f, 1, SLEEP_TIME)
+}
+
+//
+// core:sync/extended.odin
+//
+
+@test
+test_wait_group :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ step1: sync.Wait_Group,
+ step2: sync.Wait_Group,
+ i: int,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ sync.wait_group_wait(&data.step1)
+
+ n := data.i
+ intrinsics.atomic_add(&data.number, n)
+
+ sync.wait_group_done(&data.step2)
+ }
+
+ data: Data
+ data.i = -1
+ threads: [THREADS]^thread.Thread
+
+ sync.wait_group_add(&data.step1, 1)
+ sync.wait_group_add(&data.step2, THREADS)
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ time.sleep(SMALL_SLEEP_TIME)
+ data.i = 1
+ sync.wait_group_done(&data.step1)
+
+ sync.wait_group_wait(&data.step2)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.step1.counter, 0)
+ testing.expect_value(t, data.step2.counter, 0)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_wait_group_with_timeout :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ wg: sync.Wait_Group
+ sync.wait_group_wait_with_timeout(&wg, SLEEP_TIME)
+}
+
+@test
+test_barrier :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ b: sync.Barrier,
+ i: int,
+ number: int,
+
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ sync.barrier_wait(&data.b)
+
+ intrinsics.atomic_add(&data.number, data.i)
+ }
+
+ data: Data
+ data.i = -1
+ threads: [THREADS]^thread.Thread
+
+ sync.barrier_init(&data.b, THREADS + 1) // +1 for this thread, of course.
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+ time.sleep(SMALL_SLEEP_TIME)
+ data.i = 1
+ sync.barrier_wait(&data.b)
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.b.index, 0)
+ testing.expect_value(t, data.b.generation_id, 1)
+ testing.expect_value(t, data.b.thread_count, THREADS + 1)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_auto_reset :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ a: sync.Auto_Reset_Event,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("AUR-%v> entering", th.id)
+ sync.auto_reset_event_wait(&data.a)
+ // log.debugf("AUR-%v> adding", th.id)
+ data.number += 1
+ // log.debugf("AUR-%v> signalling", th.id)
+ sync.auto_reset_event_signal(&data.a)
+ // log.debugf("AUR-%v> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ // There is a chance that this test can stall if a signal is sent before
+ // all threads are queued, because it's possible for some number of threads
+ // to get to the waiting state, the signal to fire, all of the waited
+ // threads to pass successfully, then the other threads come in with no-one
+ // to run a signal.
+ //
+ // So we'll just test a fully-waited queue of cascading threads.
+ for {
+ status := intrinsics.atomic_load(&data.a.status)
+ if status == -THREADS {
+ // log.debug("All Auto_Reset_Event threads have queued.")
+ break
+ }
+ intrinsics.cpu_relax()
+ }
+
+ sync.auto_reset_event_signal(&data.a)
+
+ wait_for(threads[:])
+
+ // The last thread should leave this primitive in a signalled state.
+ testing.expect_value(t, data.a.status, 1)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_auto_reset_already_signalled :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ a: sync.Auto_Reset_Event
+ sync.auto_reset_event_signal(&a)
+ sync.auto_reset_event_wait(&a)
+ testing.expect_value(t, a.status, 0)
+}
+
+@test
+test_ticket_mutex :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ m: sync.Ticket_Mutex,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("TIC-%i> entering", th.id)
+ // intrinsics.debug_trap()
+ sync.ticket_mutex_lock(&data.m)
+ // log.debugf("TIC-%i> locked", th.id)
+ data.number += 1
+ // log.debugf("TIC-%i> unlocking", th.id)
+ sync.ticket_mutex_unlock(&data.m)
+ // log.debugf("TIC-%i> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.m.ticket, THREADS)
+ testing.expect_value(t, data.m.serving, THREADS)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_benaphore :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ b: sync.Benaphore,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+ sync.benaphore_lock(&data.b)
+ data.number += 1
+ sync.benaphore_unlock(&data.b)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.b.counter, 0)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_recursive_benaphore :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ b: sync.Recursive_Benaphore,
+ number: int,
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+
+ // log.debugf("REC_BEP-%i> entering", th.id)
+ tried1 := sync.recursive_benaphore_try_lock(&data.b)
+ for _ in 0..<3 {
+ sync.recursive_benaphore_lock(&data.b)
+ }
+ tried2 := sync.recursive_benaphore_try_lock(&data.b)
+ // log.debugf("REC_BEP-%i> locked", th.id)
+ data.number += 1
+ for _ in 0..<3 {
+ sync.recursive_benaphore_unlock(&data.b)
+ }
+ if tried1 { sync.recursive_benaphore_unlock(&data.b) }
+ if tried2 { sync.recursive_benaphore_unlock(&data.b) }
+ // log.debugf("REC_BEP-%i> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ // The benaphore should be unowned at the end.
+ testing.expect_value(t, data.b.counter, 0)
+ testing.expect_value(t, data.b.owner, 0)
+ testing.expect_value(t, data.b.recursion, 0)
+ testing.expect_value(t, data.number, THREADS)
+}
+
+@test
+test_once :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ once: sync.Once,
+ number: int,
+ }
+
+ write :: proc "contextless" (data: rawptr) {
+ data := cast(^Data)data
+ data.number += 1
+ }
+
+ p :: proc(th: ^thread.Thread) {
+ data := cast(^Data)th.data
+ // log.debugf("ONCE-%v> entering", th.id)
+ sync.once_do_with_data_contextless(&data.once, write, data)
+ // log.debugf("ONCE-%v> leaving", th.id)
+ }
+
+ data: Data
+ threads: [THREADS]^thread.Thread
+
+ for &v in threads {
+ v = thread.create(p)
+ v.data = &data
+ v.init_context = context
+ thread.start(v)
+ }
+
+ wait_for(threads[:])
+
+ testing.expect_value(t, data.once.done, true)
+ testing.expect_value(t, data.number, 1)
+}
+
+@test
+test_park :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ car: sync.Parker,
+ number: int,
+ }
+
+ data: Data
+
+ th := thread.create_and_start_with_data(&data, proc(data: rawptr) {
+ data := cast(^Data)data
+ time.sleep(SLEEP_TIME)
+ sync.unpark(&data.car)
+ data.number += 1
+ })
+
+ sync.park(&data.car)
+
+ wait_for([]^thread.Thread{ th })
+
+ PARKER_EMPTY :: 0
+ testing.expect_value(t, data.car.state, PARKER_EMPTY)
+ testing.expect_value(t, data.number, 1)
+}
+
+@test
+test_park_with_timeout :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ car: sync.Parker
+ sync.park_with_timeout(&car, SLEEP_TIME)
+}
+
+@test
+test_one_shot_event :: proc(t: ^testing.T) {
+ testing.set_fail_timeout(t, FAIL_TIME)
+
+ Data :: struct {
+ event: sync.One_Shot_Event,
+ number: int,
+ }
+
+ data: Data
+
+ th := thread.create_and_start_with_data(&data, proc(data: rawptr) {
+ data := cast(^Data)data
+ time.sleep(SLEEP_TIME)
+ sync.one_shot_event_signal(&data.event)
+ data.number += 1
+ })
+
+ sync.one_shot_event_wait(&data.event)
+
+ wait_for([]^thread.Thread{ th })
+
+ testing.expect_value(t, data.event.state, 1)
+ testing.expect_value(t, data.number, 1)
+}
diff --git a/tests/core/sys/posix/posix.odin b/tests/core/sys/posix/posix.odin
index fa30d1601..760ddc1fb 100644
--- a/tests/core/sys/posix/posix.odin
+++ b/tests/core/sys/posix/posix.odin
@@ -1,4 +1,4 @@
-//+build darwin, freebsd, openbsd, netbsd
+#+build darwin, freebsd, openbsd, netbsd
package tests_core_posix
import "base:runtime"
diff --git a/tests/core/sys/posix/structs.odin b/tests/core/sys/posix/structs.odin
index bdb1c24e3..de9511634 100644
--- a/tests/core/sys/posix/structs.odin
+++ b/tests/core/sys/posix/structs.odin
@@ -1,4 +1,4 @@
-//+build darwin, freebsd, openbsd, netbsd
+#+build darwin, freebsd, openbsd, netbsd
package tests_core_posix
import "core:log"
@@ -63,6 +63,9 @@ execute_struct_checks :: proc(t: ^testing.T) {
waiting: for {
status: i32
wpid := posix.waitpid(pid, &status, {})
+ if wpid == -1 && posix.errno() == .EINTR {
+ continue
+ }
if !testing.expectf(t, wpid != -1, "waitpid() failure: %v", posix.strerror()) {
return false
}
diff --git a/tests/core/sys/windows/test_clipboard.odin b/tests/core/sys/windows/test_clipboard.odin
new file mode 100644
index 000000000..dc482f2f8
--- /dev/null
+++ b/tests/core/sys/windows/test_clipboard.odin
@@ -0,0 +1,55 @@
+#+build windows
+package test_core_sys_windows
+
+import "core:testing"
+import win32 "core:sys/windows"
+import "base:runtime"
+import "core:strings"
+import "core:mem"
+
+read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) {
+ win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return
+
+ win32.OpenClipboard(wnd_handle) or_return
+ defer win32.CloseClipboard()
+
+ clipboard_data := win32.GetClipboardData(win32.CF_TEXT)
+ if clipboard_data != nil {
+ if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil {
+ result = strings.clone_from_cstring(cstr, allocator)
+ ok = true
+ }
+ win32.GlobalUnlock(win32.HGLOBAL(clipboard_data))
+ }
+ return
+}
+
+write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) -> win32.BOOL {
+ win32.OpenClipboard(wnd_handle) or_return
+ defer win32.CloseClipboard()
+ win32.EmptyClipboard()
+
+ h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1))
+ if h_mem == nil {return false}
+
+ cstr_dst := cast([^]u8)win32.GlobalLock(h_mem)
+ defer win32.GlobalUnlock(h_mem)
+ if cstr_dst == nil {return false}
+
+ mem.copy(rawptr(cstr_dst), raw_data(text), len(text))
+ cstr_dst[len(text)] = 0
+
+ win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem))
+ return true
+}
+
+
+@(test)
+verify_win32_clipboard :: proc(t: ^testing.T) {
+ ok1 := write_to_clipboard(nil, "Hello everynyan! OH MY GAH")
+ testing.expect_value(t, ok1, true)
+
+ clipboard_content, ok2 := read_from_clipboard(nil, context.temp_allocator)
+ testing.expect_value(t, ok2, true)
+ testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH")
+}
diff --git a/tests/core/sys/windows/test_kernel32.odin b/tests/core/sys/windows/test_kernel32.odin
index 81331fc9f..f6a88c769 100644
--- a/tests/core/sys/windows/test_kernel32.odin
+++ b/tests/core/sys/windows/test_kernel32.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows
import "base:intrinsics"
diff --git a/tests/core/sys/windows/test_ole32.odin b/tests/core/sys/windows/test_ole32.odin
index 30bf5bc80..8be231e1f 100644
--- a/tests/core/sys/windows/test_ole32.odin
+++ b/tests/core/sys/windows/test_ole32.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows
import "base:intrinsics"
diff --git a/tests/core/sys/windows/test_user32.odin b/tests/core/sys/windows/test_user32.odin
index 0778fdf41..2fe849a6b 100644
--- a/tests/core/sys/windows/test_user32.odin
+++ b/tests/core/sys/windows/test_user32.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows
import "core:testing"
diff --git a/tests/core/sys/windows/test_windows.odin b/tests/core/sys/windows/test_windows.odin
index 724b1b7af..cab36af36 100644
--- a/tests/core/sys/windows/test_windows.odin
+++ b/tests/core/sys/windows/test_windows.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows
import "base:intrinsics"
diff --git a/tests/core/sys/windows/test_windows_generated.odin b/tests/core/sys/windows/test_windows_generated.odin
index 13d09f4e1..3d8184a8b 100644
--- a/tests/core/sys/windows/test_windows_generated.odin
+++ b/tests/core/sys/windows/test_windows_generated.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows // generated by win32gen
import "core:testing"
diff --git a/tests/core/sys/windows/test_winerror.odin b/tests/core/sys/windows/test_winerror.odin
index adbdb7ce1..baabae52b 100644
--- a/tests/core/sys/windows/test_winerror.odin
+++ b/tests/core/sys/windows/test_winerror.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package test_core_sys_windows
import "core:testing"
diff --git a/tests/core/sys/windows/win32gen/win32gen.cpp b/tests/core/sys/windows/win32gen/win32gen.cpp
index 731173aa6..57a094cd5 100644
--- a/tests/core/sys/windows/win32gen/win32gen.cpp
+++ b/tests/core/sys/windows/win32gen/win32gen.cpp
@@ -902,7 +902,7 @@ static void verify_error_helpers(ofstream& out) {
}
static void test_core_sys_windows(ofstream& out) {
- out << "//+build windows" << endl
+ out << "#+build windows" << endl
<< "package " << __func__
<< " // generated by " << path(__FILE__).filename().replace_extension("").string() << endl
<< endl
diff --git a/tests/core/time/test_core_time.odin b/tests/core/time/test_core_time.odin
index c408bc582..424111aa3 100644
--- a/tests/core/time/test_core_time.odin
+++ b/tests/core/time/test_core_time.odin
@@ -197,6 +197,36 @@ test_parse_rfc3339_string :: proc(t: ^testing.T) {
}
@test
+test_print_rfc3339 :: proc(t: ^testing.T) {
+ TestCase :: struct {
+ printed: string,
+ time: i64,
+ utc_offset: int,
+ }
+
+ tests :: [?]TestCase {
+ {"1985-04-12T23:20:50.52Z", 482196050520000000, 0},
+ {"1985-04-12T23:20:50.52001905Z", 482196050520019050, 0},
+ {"1996-12-19T16:39:57-08:00", 851013597000000000, -480},
+ {"1996-12-20T00:39:57Z", 851042397000000000, 0},
+ {"1937-01-01T12:00:27.87+00:20", -1041335972130000000, +20},
+ }
+
+ for test in tests {
+ timestamp := time.Time { _nsec = test.time }
+ printed_timestamp, ok := time.time_to_rfc3339(time=timestamp, utc_offset=test.utc_offset)
+ defer delete_string(printed_timestamp)
+
+ testing.expect(t, ok, "expected printing to work fine")
+
+ testing.expectf(
+ t, printed_timestamp == test.printed,
+ "expected is %w, printed is %w", test.printed, printed_timestamp,
+ )
+ }
+}
+
+@test
test_parse_iso8601_string :: proc(t: ^testing.T) {
for test in iso8601_tests {
is_leap := false
@@ -253,6 +283,31 @@ test_parse_iso8601_string :: proc(t: ^testing.T) {
}
}
+@test
+test_time_to_datetime_roundtrip :: proc(t: ^testing.T) {
+ // Roundtrip a time through `time_to_datetime` to `DateTime` and back.
+ // Select `N` evenly-distributed points throughout the positive signed 64-bit number line.
+ N :: 1024
+ for i in 0..=i64(N) {
+ n := i * (max(i64) / N)
+ x := time.unix(0, n)
+
+ y, ttd_err := time.time_to_datetime(x)
+ testing.expectf(t, ttd_err,
+ "Time<%i> failed to convert to DateTime",
+ n) or_continue
+
+ z, dtt_err := time.datetime_to_time(y)
+ testing.expectf(t, dtt_err,
+ "DateTime<%v> failed to convert to Time",
+ y) or_continue
+
+ testing.expectf(t, x == z,
+ "Roundtrip conversion of Time to DateTime and back failed: got %v, expected %v",
+ z, x)
+ }
+}
+
MONTH_DAYS := []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
YEAR_START :: 1900
YEAR_END :: 2024
@@ -293,4 +348,4 @@ date_component_roundtrip_test :: proc(t: ^testing.T, moment: dt.DateTime) {
"Expected %4d-%2d-%2d %2d:%2d:%2d, got %4d-%2d-%2d %2d:%2d:%2d",
moment.year, moment.month, moment.day, moment.hour, moment.minute, moment.second, YYYY, MM, DD, hh, mm, ss,
)
-} \ No newline at end of file
+}
diff --git a/tests/core/unicode/test_core_unicode.odin b/tests/core/unicode/test_core_unicode.odin
index a1f6ac934..30a40b30b 100644
--- a/tests/core/unicode/test_core_unicode.odin
+++ b/tests/core/unicode/test_core_unicode.odin
@@ -16,8 +16,7 @@ run_test_cases :: proc(t: ^testing.T, test_cases: []Test_Case, loc := #caller_lo
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)
- {
+ loc = loc) {
failed += 1
}
}
diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin
index ce1849e1c..7b125d4e4 100644
--- a/tests/documentation/documentation_tester.odin
+++ b/tests/documentation/documentation_tester.odin
@@ -264,7 +264,7 @@ write_test_suite :: proc(example_tests: []Example_Test) {
test_runner := strings.builder_make()
strings.write_string(&test_runner,
-`//+private
+`#+private
package documentation_verification
import "core:os"
diff --git a/tests/issues/run.bat b/tests/issues/run.bat
index 299e08791..dcea3d483 100644
--- a/tests/issues/run.bat
+++ b/tests/issues/run.bat
@@ -15,6 +15,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
+..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
@echo off
diff --git a/tests/issues/run.sh b/tests/issues/run.sh
index 8b4c1e7f2..c3bc00e24 100755
--- a/tests/issues/run.sh
+++ b/tests/issues/run.sh
@@ -16,6 +16,7 @@ $ODIN test ../test_issue_2466.odin $COMMON
$ODIN test ../test_issue_2615.odin $COMMON
$ODIN test ../test_issue_2637.odin $COMMON
$ODIN test ../test_issue_2666.odin $COMMON
+$ODIN test ../test_issue_4210.odin $COMMON
if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
echo "SUCCESSFUL 1/1"
else
diff --git a/tests/issues/test_issue_4210.odin b/tests/issues/test_issue_4210.odin
new file mode 100644
index 000000000..f50086a4e
--- /dev/null
+++ b/tests/issues/test_issue_4210.odin
@@ -0,0 +1,85 @@
+// Tests issue #4210 https://github.com/odin-lang/Odin/issues/4210
+package test_issues
+
+import "core:testing"
+import "base:intrinsics"
+
+@test
+test_row_major_matrix :: proc(t: ^testing.T) {
+ row_major34: #row_major matrix[3,4]int = {
+ 11,12,13,14,
+ 21,22,23,24,
+ 31,32,33,34,
+ }
+ row_major34_expected := [?]int{11,12,13,14, 21,22,23,24, 31,32,33,34}
+
+ row_major43: #row_major matrix[4,3]int = {
+ 11,12,13,
+ 21,22,23,
+ 31,32,33,
+ 41,42,43,
+ }
+ row_major43_expected := [?]int{11,12,13, 21,22,23, 31,32,33, 41,42,43}
+
+ major34_flattened := intrinsics.matrix_flatten(row_major34)
+ major34_from_ptr := intrinsics.unaligned_load((^[3 * 4]int)(&row_major34))
+
+ for row in 0..<3 {
+ for column in 0..<4 {
+ idx := row * 4 + column
+ testing.expect_value(t, major34_flattened[idx], row_major34_expected[idx])
+ testing.expect_value(t, major34_from_ptr [idx], row_major34_expected[idx])
+ }
+ }
+
+ major43_flattened := intrinsics.matrix_flatten(row_major43)
+ major43_from_ptr := intrinsics.unaligned_load((^[4 * 3]int)(&row_major43))
+
+ for row in 0..<4 {
+ for column in 0..<3 {
+ idx := row * 3 + column
+ testing.expect_value(t, major43_flattened[idx], row_major43_expected[idx])
+ testing.expect_value(t, major43_from_ptr [idx], row_major43_expected[idx])
+ }
+ }
+}
+
+@test
+test_row_minor_matrix :: proc(t: ^testing.T) {
+ row_minor34: matrix[3,4]int = {
+ 11,12,13,14,
+ 21,22,23,24,
+ 31,32,33,34,
+ }
+ row_minor34_expected := [?]int{11,21,31, 12,22,32, 13,23,33, 14,24,34}
+
+ row_minor43: matrix[4,3]int = {
+ 11,12,13,
+ 21,22,23,
+ 31,32,33,
+ 41,42,43,
+ }
+ row_minor43_expected := [?]int{11,21,31,41, 12,22,32,42, 13,23,33,43}
+
+ minor34_flattened := intrinsics.matrix_flatten(row_minor34)
+ minor34_from_ptr := intrinsics.unaligned_load((^[3 * 4]int)(&row_minor34))
+
+ for row in 0..<3 {
+ for column in 0..<4 {
+ idx := row * 4 + column
+ testing.expect_value(t, minor34_flattened[idx], row_minor34_expected[idx])
+ testing.expect_value(t, minor34_from_ptr [idx], row_minor34_expected[idx])
+ }
+ }
+
+ minor43_flattened := intrinsics.matrix_flatten(row_minor43)
+ minor43_from_ptr := intrinsics.unaligned_load((^[4 * 3]int)(&row_minor43))
+
+ for row in 0..<4 {
+ for column in 0..<3 {
+ idx := row * 3 + column
+ testing.expect_value(t, minor43_flattened[idx], row_minor43_expected[idx])
+ testing.expect_value(t, minor43_from_ptr [idx], row_minor43_expected[idx])
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/vendor/all.odin b/tests/vendor/all.odin
index 1abbc5d7f..ba5628252 100644
--- a/tests/vendor/all.odin
+++ b/tests/vendor/all.odin
@@ -1,4 +1,4 @@
package tests_vendor
-@(require) import "glfw"
-@(require) import "lua/5.4" \ No newline at end of file
+@(require) import "glfw"
+@(require) import _ "lua/5.4"
diff --git a/tests/vendor/glfw/test_vendor_glfw.odin b/tests/vendor/glfw/test_vendor_glfw.odin
index 8a7fb0d0a..c1a75f1a8 100644
--- a/tests/vendor/glfw/test_vendor_glfw.odin
+++ b/tests/vendor/glfw/test_vendor_glfw.odin
@@ -1,4 +1,4 @@
-//+build darwin, windows
+#+build darwin, windows
package test_vendor_glfw
import "core:testing"
diff --git a/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin
index e331200ea..e5edca540 100644
--- a/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin
+++ b/tests/vendor/lua/5.4/test_vendor_lua.5.4.odin
@@ -1,4 +1,4 @@
-//+build windows, linux, darwin
+#+build windows, linux, darwin
package test_vendor_lua_54
import "core:testing"
diff --git a/vendor/ENet/unix.odin b/vendor/ENet/unix.odin
index 1cbda5974..210e64394 100644
--- a/vendor/ENet/unix.odin
+++ b/vendor/ENet/unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd
+#+build linux, darwin, freebsd, openbsd, netbsd
package ENet
// When we implement the appropriate bindings for Unix, the section separated
diff --git a/vendor/ENet/win32.odin b/vendor/ENet/win32.odin
index 0a1997ff9..f5a1c8985 100644
--- a/vendor/ENet/win32.odin
+++ b/vendor/ENet/win32.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package ENet
// When we implement the appropriate bindings for Windows, the section separated
diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin
index 081e0861b..c1d789273 100644
--- a/vendor/box2d/box2d.odin
+++ b/vendor/box2d/box2d.odin
@@ -3,7 +3,11 @@ package vendor_box2d
import "base:intrinsics"
import "core:c"
-@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ @(private) VECTOR_EXT :: "_simd" when #config(VENDOR_BOX2D_ENABLE_SIMD128, intrinsics.has_target_feature("simd128")) else ""
+} else {
+ @(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
+}
when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_windows_amd64_" + VECTOR_EXT + ".lib"
@@ -13,6 +17,8 @@ when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_darwin_amd64_" + VECTOR_EXT + ".a"
} else when ODIN_ARCH == .amd64 {
@(private) LIB_PATH :: "lib/box2d_other_amd64_" + VECTOR_EXT + ".a"
+} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ @(private) LIB_PATH :: "lib/box2d_wasm" + VECTOR_EXT + ".o"
} else {
@(private) LIB_PATH :: "lib/box2d_other.a"
}
@@ -21,8 +27,16 @@ when !#exists(LIB_PATH) {
#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
}
-foreign import lib {
- LIB_PATH,
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ when VECTOR_EXT == "_simd" {
+ foreign import lib "lib/box2d_wasm_simd.o"
+ } else {
+ foreign import lib "lib/box2d_wasm.o"
+ }
+} else {
+ foreign import lib {
+ LIB_PATH,
+ }
}
@@ -1520,4 +1534,4 @@ IsValid :: proc{
Joint_IsValid,
IsValidRay,
-} \ No newline at end of file
+}
diff --git a/vendor/box2d/box2d_wasm.odin b/vendor/box2d/box2d_wasm.odin
new file mode 100644
index 000000000..0fcaf753f
--- /dev/null
+++ b/vendor/box2d/box2d_wasm.odin
@@ -0,0 +1,4 @@
+#+build wasm32, wasm64p32
+package vendor_box2d
+
+@(require) import _ "vendor:libc"
diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh
index 4fa64faa0..0c5ff999d 100755
--- a/vendor/box2d/build_box2d.sh
+++ b/vendor/box2d/build_box2d.sh
@@ -11,7 +11,7 @@ tar -xzvf "v$VERSION.tar.gz"
cd "box2d-$VERSION"
-DISABLE_FLAGS="-DBOX2D_SAMPLES=OFF -DBOX2D_VALIDATE=OFF -DBOX2D_UNIT_TESTS=OFF"
+FLAGS="-DCMAKE_BUILD_TYPE=Release -DBOX2D_SAMPLES=OFF -DBOX2D_VALIDATE=OFF -DBOX2D_UNIT_TESTS=OFF"
case "$(uname -s)" in
Darwin)
@@ -21,20 +21,20 @@ Darwin)
"x86_64" | "amd64")
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
+ cmake $FLAGS -DBOX2D_AVX2=ON -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_avx2.a
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
+ cmake $FLAGS -DBOX2D_AVX2=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_sse2.a
;;
*)
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
+ cmake $FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_arm64.a
;;
@@ -45,20 +45,20 @@ Darwin)
"x86_64" | "amd64")
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -S . -B build
+ cmake $FLAGS -DBOX2D_AVX2=ON -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other_amd64_avx2.a
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -S . -B build
+ cmake $FLAGS -DBOX2D_AVX2=OFF -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other_amd64_sse2.a
;;
*)
rm -rf build
mkdir build
- cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
+ cmake $FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other.a
;;
@@ -68,5 +68,7 @@ esac
cd ..
+make -f wasm.Makefile
+
rm -rf v3.0.0.tar.gz
rm -rf box2d-3.0.0
diff --git a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a
index 2e2b72cb1..269de02fa 100644
--- a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a
+++ b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a
Binary files differ
diff --git a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a
index cd6cb1ca8..096db9d7a 100644
--- a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a
+++ b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a
Binary files differ
diff --git a/vendor/box2d/lib/box2d_darwin_arm64.a b/vendor/box2d/lib/box2d_darwin_arm64.a
index 5723290b7..4feb4aac9 100644
--- a/vendor/box2d/lib/box2d_darwin_arm64.a
+++ b/vendor/box2d/lib/box2d_darwin_arm64.a
Binary files differ
diff --git a/vendor/box2d/lib/box2d_wasm.o b/vendor/box2d/lib/box2d_wasm.o
new file mode 100755
index 000000000..15d71c5a1
--- /dev/null
+++ b/vendor/box2d/lib/box2d_wasm.o
Binary files differ
diff --git a/vendor/box2d/lib/box2d_wasm_simd.o b/vendor/box2d/lib/box2d_wasm_simd.o
new file mode 100755
index 000000000..568900bd9
--- /dev/null
+++ b/vendor/box2d/lib/box2d_wasm_simd.o
Binary files differ
diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile
new file mode 100644
index 000000000..929b61aea
--- /dev/null
+++ b/vendor/box2d/wasm.Makefile
@@ -0,0 +1,32 @@
+# Custom Makefile to build box2d for Odin's WASM targets.
+# I tried to make a cmake toolchain file for this / use cmake but this is far easier.
+# NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten.
+
+# CC = $(shell brew --prefix llvm)/bin/clang
+# LD = $(shell brew --prefix llvm)/bin/wasm-ld
+
+VERSION = 3.0.0
+SRCS = $(wildcard box2d-$(VERSION)/src/*.c)
+OBJS_SIMD = $(SRCS:.c=_simd.o)
+OBJS = $(SRCS:.c=.o)
+SYSROOT = $(shell odin root)/vendor/libc
+CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
+
+all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+%_simd.o: %.c
+ $(CC) -c $(CFLAGS) -msimd128 $< -o $@
+
+lib/box2d_wasm.o: $(OBJS)
+ $(LD) -r -o lib/box2d_wasm.o $(OBJS)
+
+lib/box2d_wasm_simd.o: $(OBJS_SIMD)
+ $(LD) -r -o lib/box2d_wasm_simd.o $(OBJS_SIMD)
+
+clean:
+ rm -rf $(OBJS) $(OBJS_SIMD)
+
+.PHONY: clean
diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin
index f4518360d..a24c36d64 100644
--- a/vendor/cgltf/cgltf.odin
+++ b/vendor/cgltf/cgltf.odin
@@ -5,6 +5,7 @@ LIB :: (
"lib/cgltf.lib" when ODIN_OS == .Windows
else "lib/cgltf.a" when ODIN_OS == .Linux
else "lib/darwin/cgltf.a" when ODIN_OS == .Darwin
+ else "lib/cgltf_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -13,7 +14,11 @@ when LIB != "" {
// Windows library is shipped with the compiler, so a Windows specific message should not be needed.
#panic("Could not find the compiled cgltf library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/cgltf/src\"`")
}
+}
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import lib "lib/cgltf_wasm.o"
+} else when LIB != "" {
foreign import lib { LIB }
} else {
foreign import lib "system:cgltf"
diff --git a/vendor/cgltf/cgltf_wasm.odin b/vendor/cgltf/cgltf_wasm.odin
new file mode 100644
index 000000000..fb612b2ac
--- /dev/null
+++ b/vendor/cgltf/cgltf_wasm.odin
@@ -0,0 +1,4 @@
+#+build wasm32, wasm64p32
+package cgltf
+
+@(require) import _ "vendor:libc"
diff --git a/vendor/cgltf/lib/cgltf_wasm.o b/vendor/cgltf/lib/cgltf_wasm.o
new file mode 100644
index 000000000..54346d176
--- /dev/null
+++ b/vendor/cgltf/lib/cgltf_wasm.o
Binary files differ
diff --git a/vendor/cgltf/src/Makefile b/vendor/cgltf/src/Makefile
index ede3d158e..0dd450ce0 100644
--- a/vendor/cgltf/src/Makefile
+++ b/vendor/cgltf/src/Makefile
@@ -6,6 +6,10 @@ else
all: unix
endif
+wasm:
+ mkdir -p ../lib
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc cgltf.c -o ../lib/cgltf_wasm.o
+
unix:
mkdir -p ../lib
$(CC) -c -O2 -Os -fPIC cgltf.c
diff --git a/vendor/commonmark/cmark.odin b/vendor/commonmark/cmark.odin
index 50544b9bd..2fdf1387c 100644
--- a/vendor/commonmark/cmark.odin
+++ b/vendor/commonmark/cmark.odin
@@ -338,7 +338,7 @@ foreign lib {
node_set_list_tight :: proc(node: ^Node, tight: b32) -> (success: b32) ---
// Returns the info string from a fenced code block.
- get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) ---
+ node_get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) ---
// Sets the info string in a fenced code block, returning `true` on success and `false` on failure.
node_set_fence_info :: proc(node: ^Node, fence_info: cstring) -> (success: b32) ---
diff --git a/vendor/commonmark/doc.odin b/vendor/commonmark/doc.odin
index 736048e56..ef788fb8f 100644
--- a/vendor/commonmark/doc.odin
+++ b/vendor/commonmark/doc.odin
@@ -1,4 +1,4 @@
-//+build ignore
+#+build ignore
/*
Bindings against CMark (https://github.com/commonmark/cmark)
diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin
index e33845b73..4e51d5203 100644
--- a/vendor/directx/d3d12/d3d12.odin
+++ b/vendor/directx/d3d12/d3d12.odin
@@ -3459,10 +3459,10 @@ DRED_DEVICE_STATE :: enum i32 {
}
DRED_PAGE_FAULT_OUTPUT2 :: struct {
- PageFaultVA: GPU_VIRTUAL_ADDRESS,
- pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1,
- pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1,
- PageFaultFlags: DRED_PAGE_FAULT_FLAGS,
+ PageFaultVA: GPU_VIRTUAL_ADDRESS,
+ pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1,
+ pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1,
+ PageFaultFlags: DRED_PAGE_FAULT_FLAGS,
}
DEVICE_REMOVED_EXTENDED_DATA1 :: struct {
diff --git a/vendor/directx/dxc/dxcapi.odin b/vendor/directx/dxc/dxcapi.odin
index 79d305ea0..23dbc8f30 100644
--- a/vendor/directx/dxc/dxcapi.odin
+++ b/vendor/directx/dxc/dxcapi.odin
@@ -476,8 +476,8 @@ IVersionInfo3_VTable :: struct {
}
ArgPair :: struct {
- pName: wstring,
- pValue: wstring,
+ pName: wstring,
+ pValue: wstring,
}
IPdbUtils_UUID_STRING :: "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D"
diff --git a/vendor/directx/dxc/dxcdef_unix.odin b/vendor/directx/dxc/dxcdef_unix.odin
index 530d03ff0..9f8afc0e8 100644
--- a/vendor/directx/dxc/dxcdef_unix.odin
+++ b/vendor/directx/dxc/dxcdef_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd
+#+build linux, darwin, freebsd, openbsd, netbsd
package directx_dxc
import "core:c"
diff --git a/vendor/directx/dxc/dxcdef_windows.odin b/vendor/directx/dxc/dxcdef_windows.odin
index 16e6f6566..45b2f9558 100644
--- a/vendor/directx/dxc/dxcdef_windows.odin
+++ b/vendor/directx/dxc/dxcdef_windows.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package directx_dxc
import win32 "core:sys/windows"
import dxgi "vendor:directx/dxgi"
diff --git a/vendor/egl/egl.odin b/vendor/egl/egl.odin
index e455a3d42..985d58457 100644
--- a/vendor/egl/egl.odin
+++ b/vendor/egl/egl.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package egl
NativeDisplayType :: distinct rawptr
diff --git a/vendor/fontstash/fontstash.odin b/vendor/fontstash/fontstash.odin
index 2c692db06..8563277b1 100644
--- a/vendor/fontstash/fontstash.odin
+++ b/vendor/fontstash/fontstash.odin
@@ -1,4 +1,4 @@
-//+vet !using-param
+#+vet !using-param
package fontstash
import "base:runtime"
diff --git a/vendor/fontstash/fontstash_os.odin b/vendor/fontstash/fontstash_os.odin
index 6182573bd..ed453926f 100644
--- a/vendor/fontstash/fontstash_os.odin
+++ b/vendor/fontstash/fontstash_os.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package fontstash
import "core:log"
diff --git a/vendor/fontstash/fontstash_other.odin b/vendor/fontstash/fontstash_other.odin
index 1c2ca3f28..edb76d9db 100644
--- a/vendor/fontstash/fontstash_other.odin
+++ b/vendor/fontstash/fontstash_other.odin
@@ -1,4 +1,4 @@
-//+build js
+#+build js
package fontstash
AddFontPath :: proc(
diff --git a/vendor/glfw/native_darwin.odin b/vendor/glfw/native_darwin.odin
index b5191a913..61b2a9cb1 100644
--- a/vendor/glfw/native_darwin.odin
+++ b/vendor/glfw/native_darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package glfw
diff --git a/vendor/glfw/native_linux.odin b/vendor/glfw/native_linux.odin
index acae8a27e..e1aebbbf7 100644
--- a/vendor/glfw/native_linux.odin
+++ b/vendor/glfw/native_linux.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package glfw
diff --git a/vendor/glfw/native_windows.odin b/vendor/glfw/native_windows.odin
index ce0dbf66f..66ed04dd7 100644
--- a/vendor/glfw/native_windows.odin
+++ b/vendor/glfw/native_windows.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package glfw
diff --git a/vendor/libc/README.md b/vendor/libc/README.md
new file mode 100644
index 000000000..1dd50c5a9
--- /dev/null
+++ b/vendor/libc/README.md
@@ -0,0 +1,12 @@
+# vendor:libc
+
+A (very small) subset of a libc implementation over Odin libraries.
+This is mainly intended for use in Odin WASM builds to allow using libraries like box2d, cgltf etc. without emscripten hacks.
+
+You can use this with clang by doing `clang -c --target=wasm32 --sysroot=$(odin root)/vendor/libc` (+ all other flags and inputs).
+This will (if all the libc usage of the library is implemented) spit out a `.o` file you can use with the foreign import system.
+If you then also make sure this package is included in the Odin side of the project (`@(require) import "vendor:libc"`) you will be able
+compile to WASM like Odin expects.
+
+This is currently used by `vendor:box2d`, `vendor:stb/image`, `vendor:stb/truetype`, `vendor:stb/rect_pack`, and `vendor:cgltf`.
+You can see how building works by looking at those.
diff --git a/vendor/libc/assert.odin b/vendor/libc/assert.odin
new file mode 100644
index 000000000..c34bd1f2d
--- /dev/null
+++ b/vendor/libc/assert.odin
@@ -0,0 +1,15 @@
+package odin_libc
+
+import "base:runtime"
+
+@(require, linkage="strong", link_name="__odin_libc_assert_fail")
+__odin_libc_assert_fail :: proc "c" (func: cstring, file: cstring, line: i32, expr: cstring) -> ! {
+ context = g_ctx
+ loc := runtime.Source_Code_Location{
+ file_path = string(file),
+ line = line,
+ column = 0,
+ procedure = string(func),
+ }
+ context.assertion_failure_proc("runtime assertion", string(expr), loc)
+}
diff --git a/vendor/libc/include/assert.h b/vendor/libc/include/assert.h
new file mode 100644
index 000000000..a6fb6c696
--- /dev/null
+++ b/vendor/libc/include/assert.h
@@ -0,0 +1,16 @@
+#ifdef NDEBUG
+#define assert(e) ((void)0)
+#else
+
+#ifdef __FILE_NAME__
+#define __ASSERT_FILE_NAME __FILE_NAME__
+#else /* __FILE_NAME__ */
+#define __ASSERT_FILE_NAME __FILE__
+#endif /* __FILE_NAME__ */
+
+void __odin_libc_assert_fail(const char *, const char *, int, const char *);
+
+#define assert(e) \
+ (__builtin_expect(!(e), 0) ? __odin_libc_assert_fail(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
+
+#endif /* NDEBUG */
diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h
new file mode 100644
index 000000000..3f60d698f
--- /dev/null
+++ b/vendor/libc/include/math.h
@@ -0,0 +1,21 @@
+#include <stdbool.h>
+
+float sqrtf(float);
+float cosf(float);
+float sinf(float);
+float atan2f(float, float);
+bool isnan(float);
+bool isinf(float);
+double floor(double x);
+double ceil(double x);
+double sqrt(double x);
+double pow(double x, double y);
+double fmod(double x, double y);
+double cos(double x);
+double acos(double x);
+double fabs(double x);
+int abs(int);
+double ldexp(double, int);
+double exp(double);
+float log(float);
+float sin(float);
diff --git a/vendor/libc/include/stdio.h b/vendor/libc/include/stdio.h
new file mode 100644
index 000000000..807437f3c
--- /dev/null
+++ b/vendor/libc/include/stdio.h
@@ -0,0 +1,47 @@
+#include <stddef.h>
+#include <stdarg.h>
+
+#pragma once
+
+typedef struct {} FILE;
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#define stdout ((FILE *)2)
+#define stderr ((FILE *)3)
+
+FILE *fopen(const char *, char *);
+int fclose(FILE *);
+int fseek(FILE *, long, int);
+long ftell(FILE *);
+size_t fread(void *, size_t, size_t, FILE *);
+size_t fwrite(const void *, size_t, size_t, FILE *);
+
+int vfprintf(FILE *, const char *, va_list);
+int vsnprintf(char *, size_t, const char *, va_list);
+
+static inline int snprintf(char *buf, size_t size, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+ return result;
+}
+
+static inline int fprintf(FILE *f, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vfprintf(f, fmt, args);
+ va_end(args);
+ return result;
+}
+
+static inline int printf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ int result = vfprintf(stdout, fmt, args);
+ va_end(args);
+ return result;
+}
diff --git a/vendor/libc/include/stdlib.h b/vendor/libc/include/stdlib.h
new file mode 100644
index 000000000..22cfc528b
--- /dev/null
+++ b/vendor/libc/include/stdlib.h
@@ -0,0 +1,19 @@
+#include <stddef.h>
+
+void *malloc(size_t size);
+
+void *aligned_alloc(size_t alignment, size_t size);
+
+void free(void *);
+
+void *realloc(void *, size_t);
+
+void qsort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*));
+
+int atoi(const char *);
+long atol(const char *);
+long long atoll(const char *);
+
+double atof(const char *);
+
+long strtol(const char *, char **, int);
diff --git a/vendor/libc/include/string.h b/vendor/libc/include/string.h
new file mode 100644
index 000000000..4571f9454
--- /dev/null
+++ b/vendor/libc/include/string.h
@@ -0,0 +1,21 @@
+#include <stddef.h>
+
+void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
+void *memmove(void *, void *, size_t);
+int memcmp(const void *, const void *, size_t);
+
+unsigned long strlen(const char *str);
+
+char *strchr(const char *, int);
+char *strrchr(const char *, int);
+
+char *strncpy(char *, const char *, size_t);
+char *strcpy(char *, const char *);
+
+size_t strcspn(const char *, const char *);
+
+int strcmp(const char *, const char *);
+int strncmp(const char *, const char *, size_t);
+
+char *strstr(const char *, const char *);
diff --git a/vendor/libc/libc.odin b/vendor/libc/libc.odin
new file mode 100644
index 000000000..00d687109
--- /dev/null
+++ b/vendor/libc/libc.odin
@@ -0,0 +1,25 @@
+package odin_libc
+
+import "base:runtime"
+
+import "core:mem"
+
+@(private)
+g_ctx: runtime.Context
+@(private)
+g_allocator: mem.Compat_Allocator
+
+@(init)
+init_context :: proc() {
+ g_ctx = context
+
+ // Wrapping the allocator with the mem.Compat_Allocator so we can
+ // mimic the realloc semantics.
+ mem.compat_allocator_init(&g_allocator, g_ctx.allocator)
+ g_ctx.allocator = mem.compat_allocator(&g_allocator)
+}
+
+// NOTE: the allocator must respect an `old_size` of `-1` on resizes!
+set_context :: proc(ctx := context) {
+ g_ctx = ctx
+}
diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin
new file mode 100644
index 000000000..59f42dd67
--- /dev/null
+++ b/vendor/libc/math.odin
@@ -0,0 +1,100 @@
+package odin_libc
+
+import "base:builtin"
+
+import "core:math"
+
+@(require, linkage="strong", link_name="sqrtf")
+sqrtf :: proc "c" (v: f32) -> f32 {
+ return math.sqrt(v)
+}
+
+@(require, linkage="strong", link_name="cosf")
+cosf :: proc "c" (v: f32) -> f32 {
+ return math.cos(v)
+}
+
+@(require, linkage="strong", link_name="sinf")
+sinf :: proc "c" (v: f32) -> f32 {
+ return math.sin(v)
+}
+
+@(require, linkage="strong", link_name="atan2f")
+atan2f :: proc "c" (v: f32, v2: f32) -> f32 {
+ return math.atan2(v, v2)
+}
+
+@(require, linkage="strong", link_name="isnan")
+isnan :: proc "c" (v: f32) -> bool {
+ return math.is_nan(v)
+}
+
+@(require, linkage="strong", link_name="isinf")
+isinf :: proc "c" (v: f32) -> bool {
+ return math.is_inf(v)
+}
+
+@(require, linkage="strong", link_name="sqrt")
+sqrt :: proc "c" (x: f64) -> f64 {
+ return math.sqrt(x)
+}
+
+@(require, linkage="strong", link_name="floor")
+floor :: proc "c" (x: f64) -> f64 {
+ return math.floor(x)
+}
+
+@(require, linkage="strong", link_name="ceil")
+ceil :: proc "c" (x: f64) -> f64 {
+ return math.ceil(x)
+}
+
+@(require, linkage="strong", link_name="pow")
+pow :: proc "c" (x, y: f64) -> f64 {
+ return math.pow(x, y)
+}
+
+@(require, linkage="strong", link_name="fmod")
+fmod :: proc "c" (x, y: f64) -> f64 {
+ return math.mod(x, y)
+}
+
+@(require, linkage="strong", link_name="cos")
+cos :: proc "c" (x: f64) -> f64 {
+ return math.cos(x)
+}
+
+@(require, linkage="strong", link_name="acos")
+acos :: proc "c" (x: f64) -> f64 {
+ return math.acos(x)
+}
+
+@(require, linkage="strong", link_name="fabs")
+fabs :: proc "c" (x: f64) -> f64 {
+ return math.abs(x)
+}
+
+@(require, linkage="strong", link_name="abs")
+abs :: proc "c" (x: i32) -> i32 {
+ return builtin.abs(x)
+}
+
+@(require, linkage="strong", link_name="ldexp")
+ldexp :: proc "c" (x: f64, y: i32) -> f64{
+ return math.ldexp(x, int(y))
+}
+
+@(require, linkage="strong", link_name="exp")
+exp :: proc "c" (x: f64) -> f64 {
+ return math.exp(x)
+}
+
+@(require, linkage="strong", link_name="log")
+log :: proc "c" (x: f32) -> f32 {
+ return math.ln(x)
+}
+
+@(require, linkage="strong", link_name="sin")
+sin :: proc "c" (x: f32) -> f32 {
+ return math.sin(x)
+}
diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin
new file mode 100644
index 000000000..10b95b96b
--- /dev/null
+++ b/vendor/libc/stdio.odin
@@ -0,0 +1,106 @@
+package odin_libc
+
+import "core:c"
+import "core:io"
+import "core:os"
+
+import stb "vendor:stb/sprintf"
+
+FILE :: uintptr
+
+@(require, linkage="strong", link_name="fopen")
+fopen :: proc "c" (path: cstring, mode: cstring) -> FILE {
+ context = g_ctx
+ unimplemented("odin_libc.fopen")
+}
+
+@(require, linkage="strong", link_name="fseek")
+fseek :: proc "c" (file: FILE, offset: c.long, whence: i32) -> i32 {
+ context = g_ctx
+ handle := os.Handle(file-1)
+ _, err := os.seek(handle, i64(offset), int(whence))
+ if err != nil {
+ return -1
+ }
+ return 0
+}
+
+@(require, linkage="strong", link_name="ftell")
+ftell :: proc "c" (file: FILE) -> c.long {
+ context = g_ctx
+ handle := os.Handle(file-1)
+ off, err := os.seek(handle, 0, os.SEEK_CUR)
+ if err != nil {
+ return -1
+ }
+ return c.long(off)
+}
+
+@(require, linkage="strong", link_name="fclose")
+fclose :: proc "c" (file: FILE) -> i32 {
+ context = g_ctx
+ handle := os.Handle(file-1)
+ if os.close(handle) != nil {
+ return -1
+ }
+ return 0
+}
+
+@(require, linkage="strong", link_name="fread")
+fread :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint {
+ context = g_ctx
+ handle := os.Handle(file-1)
+ n, _ := os.read(handle, buffer[:min(size, count)])
+ return uint(max(0, n))
+}
+
+@(require, linkage="strong", link_name="fwrite")
+fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint {
+ context = g_ctx
+ handle := os.Handle(file-1)
+ n, _ := os.write(handle, buffer[:min(size, count)])
+ return uint(max(0, n))
+}
+
+@(require, linkage="strong", link_name="vsnprintf")
+vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list) -> i32 {
+ i32_count := i32(count)
+ assert_contextless(i32_count >= 0)
+ return stb.vsnprintf(buf, i32_count, fmt, args)
+}
+
+@(require, linkage="strong", link_name="vfprintf")
+vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 {
+ context = g_ctx
+
+ handle := os.Handle(file-1)
+
+ MAX_STACK :: 4096
+
+ buf: []byte
+ stack_buf: [MAX_STACK]byte = ---
+ {
+ n := stb.vsnprintf(&stack_buf[0], MAX_STACK, fmt, args)
+ if n <= 0 {
+ return n
+ }
+
+ if n >= MAX_STACK {
+ buf = make([]byte, n)
+ n2 := stb.vsnprintf(raw_data(buf), i32(len(buf)), fmt, args)
+ assert(n == n2)
+ } else {
+ buf = stack_buf[:n]
+ }
+ }
+ defer if len(buf) > MAX_STACK {
+ delete(buf)
+ }
+
+ _, err := io.write_full(os.stream_from_handle(handle), buf)
+ if err != nil {
+ return -1
+ }
+
+ return i32(len(buf))
+}
diff --git a/vendor/libc/stdlib.odin b/vendor/libc/stdlib.odin
new file mode 100644
index 000000000..54590c1c9
--- /dev/null
+++ b/vendor/libc/stdlib.odin
@@ -0,0 +1,119 @@
+package odin_libc
+
+import "base:runtime"
+
+import "core:c"
+import "core:slice"
+import "core:sort"
+import "core:strconv"
+import "core:strings"
+
+@(require, linkage="strong", link_name="malloc")
+malloc :: proc "c" (size: uint) -> rawptr {
+ context = g_ctx
+ ptr, err := runtime.mem_alloc_non_zeroed(int(size))
+ assert(err == nil, "allocation failure")
+ return raw_data(ptr)
+}
+
+@(require, linkage="strong", link_name="aligned_alloc")
+aligned_alloc :: proc "c" (alignment: uint, size: uint) -> rawptr {
+ context = g_ctx
+ ptr, err := runtime.mem_alloc_non_zeroed(int(size), int(alignment))
+ assert(err == nil, "allocation failure")
+ return raw_data(ptr)
+}
+
+@(require, linkage="strong", link_name="free")
+free :: proc "c" (ptr: rawptr) {
+ context = g_ctx
+ runtime.mem_free(ptr)
+}
+
+@(require, linkage="strong", link_name="realloc")
+realloc :: proc "c" (ptr: rawptr, new_size: uint) -> rawptr {
+ context = g_ctx
+ // -1 for the old_size, assumed to be wrapped with the mem.Compat_Allocator to get the right size.
+ // Note that realloc does not actually care about alignment and is allowed to just align it to something
+ // else than the original allocation.
+ ptr, err := runtime.non_zero_mem_resize(ptr, -1, int(new_size))
+ assert(err == nil, "realloc failure")
+ return raw_data(ptr)
+}
+
+@(require, linkage="strong", link_name="qsort")
+qsort :: proc "c" (base: rawptr, num: uint, size: uint, cmp: proc "c" (a, b: rawptr) -> i32) {
+ context = g_ctx
+
+ 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="atoi")
+atoi :: proc "c" (str: cstring) -> i32 {
+ return i32(atoll(str))
+}
+
+@(require, linkage="strong", link_name="atol")
+atol :: proc "c" (str: cstring) -> c.long {
+ return c.long(atoll(str))
+}
+
+@(require, linkage="strong", link_name="atoll")
+atoll :: proc "c" (str: cstring) -> c.longlong {
+ context = g_ctx
+
+ sstr := string(str)
+ sstr = strings.trim_left_space(sstr)
+ i, _ := strconv.parse_i64_of_base(sstr, 10)
+ return c.longlong(i)
+}
+
+@(require, linkage="strong", link_name="atof")
+atof :: proc "c" (str: cstring) -> f64 {
+ context = g_ctx
+
+ sstr := string(str)
+ sstr = strings.trim_left_space(sstr)
+ f, _ := strconv.parse_f64(sstr)
+ return f
+}
+
+@(require, linkage="strong", link_name="strtol")
+strtol :: proc "c" (str: cstring, str_end: ^cstring, base: i32) -> c.long {
+ context = g_ctx
+
+ sstr := string(str)
+ sstr = strings.trim_left_space(sstr)
+
+ n: int
+ i, _ := strconv.parse_i64_of_base(sstr, int(base), &n)
+ str_end ^= cstring(raw_data(sstr)[n:])
+ return c.long(clamp(i, i64(min(c.long)), i64(max(c.long))))
+}
diff --git a/vendor/libc/string.odin b/vendor/libc/string.odin
new file mode 100644
index 000000000..1ab0803da
--- /dev/null
+++ b/vendor/libc/string.odin
@@ -0,0 +1,111 @@
+package odin_libc
+
+import "base:intrinsics"
+
+import "core:c"
+import "core:strings"
+import "core:mem"
+
+// NOTE: already defined by Odin.
+// void *memcpy(void *, const void *, size_t);
+// void *memset(void *, int, size_t);
+
+@(require, linkage="strong", link_name="memcmp")
+memcmp :: proc "c" (lhs: [^]byte, rhs: [^]byte, count: uint) -> i32 {
+ icount := int(count)
+ assert_contextless(icount >= 0)
+ return i32(mem.compare(lhs[:icount], rhs[:icount]))
+}
+
+@(require, linkage="strong", link_name="strlen")
+strlen :: proc "c" (str: cstring) -> c.ulong {
+ return c.ulong(len(str))
+}
+
+@(require, linkage="strong", link_name="strchr")
+strchr :: proc "c" (str: cstring, ch: i32) -> cstring {
+ bch := u8(ch)
+ sstr := string(str)
+ if bch == 0 {
+ return cstring(raw_data(sstr)[len(sstr):])
+ }
+
+ idx := strings.index_byte(sstr, bch)
+ if idx < 0 {
+ return nil
+ }
+
+ return cstring(raw_data(sstr)[idx:])
+}
+
+@(require, linkage="strong", link_name="strrchr")
+strrchr :: proc "c" (str: cstring, ch: i32) -> cstring {
+ bch := u8(ch)
+ sstr := string(str)
+ if bch == 0 {
+ return cstring(raw_data(sstr)[len(sstr):])
+ }
+
+ idx := strings.last_index_byte(sstr, bch)
+ if idx < 0 {
+ return nil
+ }
+
+ return cstring(raw_data(sstr)[idx:])
+}
+
+@(require, linkage="strong", link_name="strncpy")
+strncpy :: proc "c" (dst: [^]byte, src: cstring, count: uint) -> cstring {
+ icount := int(count)
+ assert_contextless(icount >= 0)
+ cnt := min(len(src), icount)
+ intrinsics.mem_copy_non_overlapping(dst, rawptr(src), cnt)
+ intrinsics.mem_zero(dst, icount-cnt)
+ return cstring(dst)
+}
+
+@(require, linkage="strong", link_name="strcpy")
+strcpy :: proc "c" (dst: [^]byte, src: cstring) -> cstring {
+ intrinsics.mem_copy_non_overlapping(dst, rawptr(src), len(src)+1)
+ return cstring(dst)
+}
+
+@(require, linkage="strong", link_name="strcspn")
+strcspn :: proc "c" (dst: cstring, src: cstring) -> uint {
+ context = g_ctx
+ sdst := string(dst)
+ idx := strings.index_any(sdst, string(src))
+ if idx == -1 {
+ return len(sdst)
+ }
+ return uint(idx)
+}
+
+@(require, linkage="strong", link_name="strncmp")
+strncmp :: proc "c" (lhs: cstring, rhs: cstring, count: uint) -> i32 {
+ icount := int(count)
+ assert_contextless(icount >= 0)
+ lhss := strings.string_from_null_terminated_ptr(([^]byte)(lhs), icount)
+ rhss := strings.string_from_null_terminated_ptr(([^]byte)(rhs), icount)
+ return i32(strings.compare(lhss, rhss))
+}
+
+@(require, linkage="strong", link_name="strcmp")
+strcmp :: proc "c" (lhs: cstring, rhs: cstring) -> i32 {
+ return i32(strings.compare(string(lhs), string(rhs)))
+}
+
+@(require, linkage="strong", link_name="strstr")
+strstr :: proc "c" (str: cstring, substr: cstring) -> cstring {
+ if substr == "" {
+ return str
+ }
+
+ idx := strings.index(string(str), string(substr))
+ if idx < 0 {
+ return nil
+ }
+
+ return cstring(([^]byte)(str)[idx:])
+}
+
diff --git a/vendor/lua/5.4/lua.odin b/vendor/lua/5.4/lua.odin
index 9be8fea55..a45de4d49 100644
--- a/vendor/lua/5.4/lua.odin
+++ b/vendor/lua/5.4/lua.odin
@@ -575,7 +575,7 @@ PRELOAD_TABLE :: "_PRELOAD"
L_Reg :: struct {
name: cstring,
- func: CFunction,
+ func: CFunction,
}
L_NUMSIZES :: size_of(Integer)*16 + size_of(Number)
diff --git a/vendor/miniaudio/common_unix.odin b/vendor/miniaudio/common_unix.odin
index 89699a30d..8afcc0b5a 100644
--- a/vendor/miniaudio/common_unix.odin
+++ b/vendor/miniaudio/common_unix.odin
@@ -1,4 +1,4 @@
-//+build !windows
+#+build !windows
package miniaudio
import "core:sys/unix"
diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin
index 4860680c9..f1fa279ac 100644
--- a/vendor/miniaudio/decoding.odin
+++ b/vendor/miniaudio/decoding.odin
@@ -69,9 +69,9 @@ decoder :: struct {
outputSampleRate: u32,
converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */
pInputCache: rawptr, /* In input format. Can be null if it's not needed. */
- inputCacheCap: u64, /* The capacity of the input cache. */
- inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
- inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
+ inputCacheCap: u64, /* The capacity of the input cache. */
+ inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
+ inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
allocationCallbacks: allocation_callbacks,
data: struct #raw_union {
vfs: struct {
diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin
index 857e53ff5..eae804720 100644
--- a/vendor/miniaudio/device_io_types.odin
+++ b/vendor/miniaudio/device_io_types.odin
@@ -381,7 +381,7 @@ device_config :: struct {
noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */
noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */
- noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
+ noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
dataCallback: device_data_proc,
notificationCallback: device_notification_proc,
stopCallback: stop_proc,
@@ -813,7 +813,7 @@ context_type :: struct {
/*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr,
pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
- pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
+ pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
} when SUPPORT_PULSEAUDIO else struct {}),
jack: (struct {
@@ -1140,7 +1140,7 @@ device :: struct {
pulse: (struct {
/*pa_mainloop**/ pMainLoop: rawptr,
- /*pa_context**/ pPulseContext: rawptr,
+ /*pa_context**/ pPulseContext: rawptr,
/*pa_stream**/ pStreamPlayback: rawptr,
/*pa_stream**/ pStreamCapture: rawptr,
} when SUPPORT_PULSEAUDIO else struct {}),
diff --git a/vendor/nanovg/gl/gl.odin b/vendor/nanovg/gl/gl.odin
index 48998bda5..5af7ed4bc 100644
--- a/vendor/nanovg/gl/gl.odin
+++ b/vendor/nanovg/gl/gl.odin
@@ -1,4 +1,4 @@
-//+build windows, linux, darwin
+#+build windows, linux, darwin
package nanovg_gl
import "core:log"
diff --git a/vendor/nanovg/nanovg.odin b/vendor/nanovg/nanovg.odin
index 15611cfef..540ca47cf 100644
--- a/vendor/nanovg/nanovg.odin
+++ b/vendor/nanovg/nanovg.odin
@@ -1,4 +1,4 @@
-//+build windows, linux, darwin
+#+build windows, linux, darwin
package nanovg
// TODO rename structs to old nanovg style!
diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin
index cff590b7f..8d26c8824 100644
--- a/vendor/raylib/raylib.odin
+++ b/vendor/raylib/raylib.odin
@@ -84,7 +84,6 @@ package raylib
import "core:c"
import "core:fmt"
import "core:mem"
-import "core:strings"
import "core:math/linalg"
_ :: linalg
@@ -447,9 +446,9 @@ VrStereoConfig :: struct #align(4) {
// File path list
FilePathList :: struct {
- capacity: c.uint, // Filepaths max entries
- count: c.uint, // Filepaths entries count
- paths: [^]cstring, // Filepaths entries
+ capacity: c.uint, // Filepaths max entries
+ count: c.uint, // Filepaths entries count
+ paths: [^]cstring, // Filepaths entries
}
// Automation event
@@ -1029,7 +1028,6 @@ foreign lib {
SetTraceLogLevel :: proc(logLevel: TraceLogLevel) --- // Set the current threshold (minimum) log level
MemAlloc :: proc(size: c.uint) -> rawptr --- // Internal memory allocator
MemRealloc :: proc(ptr: rawptr, size: c.uint) -> rawptr --- // Internal memory reallocator
- MemFree :: proc(ptr: rawptr) --- // Internal memory free
// Set custom callbacks
// WARNING: Callbacks setup is intended for advance users
@@ -1256,7 +1254,7 @@ foreign lib {
LoadImage :: proc(fileName: cstring) -> Image --- // Load image from file into CPU memory (RAM)
LoadImageRaw :: proc(fileName: cstring, width, height: c.int, format: PixelFormat, headerSize: c.int) -> Image --- // Load image from RAW file data
LoadImageSvg :: proc(fileNameOrString: cstring, width, height: c.int) -> Image --- // Load image from SVG file data or string with specified size
- LoadImageAnim :: proc(fileName: cstring, frames: [^]c.int) -> Image --- // Load image sequence from file (frames appended to image.data)
+ LoadImageAnim :: proc(fileName: cstring, frames: ^c.int) -> Image --- // Load image sequence from file (frames appended to image.data)
LoadImageFromMemory :: proc(fileType: cstring, fileData: rawptr, dataSize: c.int) -> Image --- // Load image from memory buffer, fileType refers to extension: i.e. '.png'
LoadImageFromTexture :: proc(texture: Texture2D) -> Image --- // Load image from GPU texture data
LoadImageFromScreen :: proc() -> Image --- // Load image from screen buffer and (screenshot)
@@ -1684,8 +1682,25 @@ TextFormat :: proc(text: cstring, args: ..any) -> cstring {
// Text formatting with variables (sprintf style) and allocates (must be freed with 'MemFree')
TextFormatAlloc :: proc(text: cstring, args: ..any) -> cstring {
- str := fmt.tprintf(string(text), ..args)
- return strings.clone_to_cstring(str, MemAllocator())
+ return fmt.caprintf(string(text), ..args, allocator=MemAllocator())
+}
+
+
+// Internal memory free
+MemFree :: proc{
+ MemFreePtr,
+ MemFreeCstring,
+}
+
+
+@(default_calling_convention="c")
+foreign lib {
+ @(link_name="MemFree")
+ MemFreePtr :: proc(ptr: rawptr) ---
+}
+
+MemFreeCstring :: proc "c" (s: cstring) {
+ MemFreePtr(rawptr(s))
}
diff --git a/vendor/sdl2/sdl2.odin b/vendor/sdl2/sdl2.odin
index 73d95e18a..b23389a64 100644
--- a/vendor/sdl2/sdl2.odin
+++ b/vendor/sdl2/sdl2.odin
@@ -41,6 +41,12 @@ MAJOR_VERSION :: 2
MINOR_VERSION :: 0
PATCHLEVEL :: 16
+VERSION :: proc "contextless" (ver: ^version) {
+ ver.major = MAJOR_VERSION
+ ver.minor = MINOR_VERSION
+ ver.patch = PATCHLEVEL
+}
+
@(default_calling_convention="c", link_prefix="SDL_")
foreign lib {
GetVersion :: proc(ver: ^version) ---
diff --git a/vendor/sdl2/sdl_events.odin b/vendor/sdl2/sdl_events.odin
index 60daaea56..b4c92683c 100644
--- a/vendor/sdl2/sdl_events.odin
+++ b/vendor/sdl2/sdl_events.odin
@@ -171,9 +171,9 @@ KeyboardEvent :: struct {
TEXTEDITINGEVENT_TEXT_SIZE :: 32
TextEditingEvent :: struct {
type: EventType, /**< ::SDL_TEXTEDITING */
- timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
- windowID: u32, /**< The window with keyboard focus, if any */
- text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */
+ timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
+ windowID: u32, /**< The window with keyboard focus, if any */
+ text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */
start: i32, /**< The start cursor of selected editing text */
length: i32, /**< The length of selected editing text */
}
@@ -184,7 +184,7 @@ TextInputEvent :: struct {
type: EventType, /**< ::SDL_TEXTINPUT */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */
- text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */
+ text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */
}
MouseMotionEvent :: struct {
diff --git a/vendor/sdl2/sdl_gamecontroller.odin b/vendor/sdl2/sdl_gamecontroller.odin
index 8772faa26..beb7d5ce7 100644
--- a/vendor/sdl2/sdl_gamecontroller.odin
+++ b/vendor/sdl2/sdl_gamecontroller.odin
@@ -54,29 +54,29 @@ GameControllerAxis :: enum c.int {
}
GameControllerButton :: enum c.int {
- INVALID = -1,
- A,
- B,
- X,
- Y,
- BACK,
- GUIDE,
- START,
- LEFTSTICK,
- RIGHTSTICK,
- LEFTSHOULDER,
- RIGHTSHOULDER,
- DPAD_UP,
- DPAD_DOWN,
- DPAD_LEFT,
- DPAD_RIGHT,
- MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
- PADDLE1, /* Xbox Elite paddle P1 */
- PADDLE2, /* Xbox Elite paddle P3 */
- PADDLE3, /* Xbox Elite paddle P2 */
- PADDLE4, /* Xbox Elite paddle P4 */
- TOUCHPAD, /* PS4/PS5 touchpad button */
- MAX,
+ INVALID = -1,
+ A,
+ B,
+ X,
+ Y,
+ BACK,
+ GUIDE,
+ START,
+ LEFTSTICK,
+ RIGHTSTICK,
+ LEFTSHOULDER,
+ RIGHTSHOULDER,
+ DPAD_UP,
+ DPAD_DOWN,
+ DPAD_LEFT,
+ DPAD_RIGHT,
+ MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
+ PADDLE1, /* Xbox Elite paddle P1 */
+ PADDLE2, /* Xbox Elite paddle P3 */
+ PADDLE3, /* Xbox Elite paddle P2 */
+ PADDLE4, /* Xbox Elite paddle P4 */
+ TOUCHPAD, /* PS4/PS5 touchpad button */
+ MAX,
}
diff --git a/vendor/sdl2/sdl_touch.odin b/vendor/sdl2/sdl_touch.odin
index f2a8cc695..f0ca69333 100644
--- a/vendor/sdl2/sdl_touch.odin
+++ b/vendor/sdl2/sdl_touch.odin
@@ -19,10 +19,10 @@ TouchDeviceType :: enum c.int {
}
Finger :: struct {
- id: FingerID,
- x: f32,
- y: f32,
- pressure: f32,
+ id: FingerID,
+ x: f32,
+ y: f32,
+ pressure: f32,
}
TOUCH_MOUSEID :: ~u32(0)
diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin
index 828a1c2bd..0c2ad7d05 100644
--- a/vendor/stb/image/stb_image.odin
+++ b/vendor/stb/image/stb_image.odin
@@ -7,6 +7,7 @@ LIB :: (
"../lib/stb_image.lib" when ODIN_OS == .Windows
else "../lib/stb_image.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image.a" when ODIN_OS == .Darwin
+ else "../lib/stb_image_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,12 +16,18 @@ when LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
+}
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import stbi "../lib/stb_image_wasm.o"
+} else when LIB != "" {
foreign import stbi { LIB }
} else {
foreign import stbi "system:stb_image"
}
+NO_STDIO :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
+
#assert(size_of(c.int) == size_of(b32))
#assert(size_of(b32) == size_of(c.int))
@@ -33,14 +40,48 @@ Io_Callbacks :: struct {
eof: proc "c" (user: rawptr) -> c.int, // returns nonzero if we are at end of file/data
}
+when !NO_STDIO {
+ @(default_calling_convention="c", link_prefix="stbi_")
+ foreign stbi {
+ ////////////////////////////////////
+ //
+ // 8-bits-per-channel interface
+ //
+ load :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
+ load_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
+
+ ////////////////////////////////////
+ //
+ // 16-bits-per-channel interface
+ //
+ load_16 :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
+ load_16_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
+
+ ////////////////////////////////////
+ //
+ // float-per-channel interface
+ //
+ loadf :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
+ loadf_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
+
+ is_hdr :: proc(filename: cstring) -> c.int ---
+ is_hdr_from_file :: proc(f: ^c.FILE) -> c.int ---
+
+ // get image dimensions & components without fully decoding
+ info :: proc(filename: cstring, x, y, comp: ^c.int) -> c.int ---
+ info_from_file :: proc(f: ^c.FILE, x, y, comp: ^c.int) -> c.int ---
+
+ is_16_bit :: proc(filename: cstring) -> b32 ---
+ is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 ---
+ }
+}
+
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbi {
////////////////////////////////////
//
// 8-bits-per-channel interface
//
- load :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
- load_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
load_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]byte ---
@@ -50,8 +91,6 @@ foreign stbi {
//
// 16-bits-per-channel interface
//
- load_16 :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
- load_16_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
load_16_from_callbacks :: proc(clbk: ^Io_Callbacks, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]u16 ---
@@ -59,8 +98,6 @@ foreign stbi {
//
// float-per-channel interface
//
- loadf :: proc(filename: cstring, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
- loadf_from_file :: proc(f: ^c.FILE, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
loadf_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, channels_in_file: ^c.int, desired_channels: c.int) -> [^]f32 ---
@@ -73,9 +110,6 @@ foreign stbi {
is_hdr_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr) -> c.int ---
is_hdr_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int ---
- is_hdr :: proc(filename: cstring) -> c.int ---
- is_hdr_from_file :: proc(f: ^c.FILE) -> c.int ---
-
// get a VERY brief reason for failure
// NOT THREADSAFE
failure_reason :: proc() -> cstring ---
@@ -84,13 +118,9 @@ foreign stbi {
image_free :: proc(retval_from_load: rawptr) ---
// get image dimensions & components without fully decoding
- info :: proc(filename: cstring, x, y, comp: ^c.int) -> c.int ---
- info_from_file :: proc(f: ^c.FILE, x, y, comp: ^c.int) -> c.int ---
info_from_memory :: proc(buffer: [^]byte, len: c.int, x, y, comp: ^c.int) -> c.int ---
info_from_callbacks :: proc(clbk: ^Io_Callbacks, user: rawptr, x, y, comp: ^c.int) -> c.int ---
- is_16_bit :: proc(filename: cstring) -> b32 ---
- is_16_bit_from_file :: proc(f: ^c.FILE) -> b32 ---
is_16_bit_from_memory :: proc(buffer: [^]byte, len: c.int) -> c.int ---
// for image formats that explicitly notate that they have premultiplied alpha,
diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin
index d407a1852..241a93eb0 100644
--- a/vendor/stb/image/stb_image_resize.odin
+++ b/vendor/stb/image/stb_image_resize.odin
@@ -1,12 +1,13 @@
package stb_image
-import c "core:c/libc"
+import "core:c"
@(private)
RESIZE_LIB :: (
"../lib/stb_image_resize.lib" when ODIN_OS == .Windows
else "../lib/stb_image_resize.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image_resize.a" when ODIN_OS == .Darwin
+ else "../lib/stb_image_resize_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,7 +16,11 @@ when RESIZE_LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
+}
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import lib "../lib/stb_image_resize_wasm.o"
+} else when RESIZE_LIB != "" {
foreign import lib { RESIZE_LIB }
} else {
foreign import lib "system:stb_image_resize"
@@ -166,7 +171,7 @@ datatype :: enum c.int {
UINT32,
FLOAT,
- MAX_TYPES,
+ MAX_TYPES,
}
@(default_calling_convention="c", link_prefix="stbir_")
diff --git a/vendor/stb/image/stb_image_wasm.odin b/vendor/stb/image/stb_image_wasm.odin
new file mode 100644
index 000000000..f43012383
--- /dev/null
+++ b/vendor/stb/image/stb_image_wasm.odin
@@ -0,0 +1,4 @@
+#+build wasm32, wasm64p32
+package stb_image
+
+@(require) import _ "vendor:libc"
diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin
index f030f1e28..e86fa2b95 100644
--- a/vendor/stb/image/stb_image_write.odin
+++ b/vendor/stb/image/stb_image_write.odin
@@ -1,12 +1,13 @@
package stb_image
-import c "core:c/libc"
+import "core:c"
@(private)
WRITE_LIB :: (
"../lib/stb_image_write.lib" when ODIN_OS == .Windows
else "../lib/stb_image_write.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_image_write.a" when ODIN_OS == .Darwin
+ else "../lib/stb_image_write_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,7 +16,11 @@ when WRITE_LIB != "" {
// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
+}
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import stbiw "../lib/stb_image_write_wasm.o"
+} else when WRITE_LIB != "" {
foreign import stbiw { WRITE_LIB }
} else {
foreign import stbiw "system:stb_image_write"
@@ -25,12 +30,6 @@ write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)
@(default_calling_convention="c", link_prefix="stbi_")
foreign stbiw {
- write_png :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
- write_bmp :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
- write_tga :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
- write_hdr :: proc(filename: cstring, w, h, comp: c.int, data: [^]f32) -> c.int ---
- write_jpg :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
-
write_png_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
write_bmp_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
write_tga_to_func :: proc(func: write_func, ctx: rawptr, w, h, comp: c.int, data: rawptr) -> c.int ---
@@ -39,3 +38,14 @@ foreign stbiw {
flip_vertically_on_write :: proc(flip_boolean: b32) ---
}
+
+when !NO_STDIO {
+ @(default_calling_convention="c", link_prefix="stbi_")
+ foreign stbiw {
+ write_png :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, stride_in_bytes: c.int) -> c.int ---
+ write_bmp :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
+ write_tga :: proc(filename: cstring, w, h, comp: c.int, data: rawptr) -> c.int ---
+ write_hdr :: proc(filename: cstring, w, h, comp: c.int, data: [^]f32) -> c.int ---
+ write_jpg :: proc(filename: cstring, w, h, comp: c.int, data: rawptr, quality: c.int /*0..=100*/) -> c.int ---
+ }
+}
diff --git a/vendor/stb/lib/darwin/stb_truetype.a b/vendor/stb/lib/darwin/stb_truetype.a
index f871693d0..b55fbe5d3 100644
--- a/vendor/stb/lib/darwin/stb_truetype.a
+++ b/vendor/stb/lib/darwin/stb_truetype.a
Binary files differ
diff --git a/vendor/stb/lib/stb_image_resize_wasm.o b/vendor/stb/lib/stb_image_resize_wasm.o
new file mode 100644
index 000000000..1bf91266b
--- /dev/null
+++ b/vendor/stb/lib/stb_image_resize_wasm.o
Binary files differ
diff --git a/vendor/stb/lib/stb_image_wasm.o b/vendor/stb/lib/stb_image_wasm.o
new file mode 100644
index 000000000..cd7fa31ce
--- /dev/null
+++ b/vendor/stb/lib/stb_image_wasm.o
Binary files differ
diff --git a/vendor/stb/lib/stb_image_write_wasm.o b/vendor/stb/lib/stb_image_write_wasm.o
new file mode 100644
index 000000000..279803330
--- /dev/null
+++ b/vendor/stb/lib/stb_image_write_wasm.o
Binary files differ
diff --git a/vendor/stb/lib/stb_rect_pack_wasm.o b/vendor/stb/lib/stb_rect_pack_wasm.o
new file mode 100644
index 000000000..fdd6d95d6
--- /dev/null
+++ b/vendor/stb/lib/stb_rect_pack_wasm.o
Binary files differ
diff --git a/vendor/stb/lib/stb_sprintf_wasm.o b/vendor/stb/lib/stb_sprintf_wasm.o
new file mode 100644
index 000000000..4c8e140e5
--- /dev/null
+++ b/vendor/stb/lib/stb_sprintf_wasm.o
Binary files differ
diff --git a/vendor/stb/lib/stb_truetype.lib b/vendor/stb/lib/stb_truetype.lib
index d4139c707..16ecf944d 100644
--- a/vendor/stb/lib/stb_truetype.lib
+++ b/vendor/stb/lib/stb_truetype.lib
Binary files differ
diff --git a/vendor/stb/lib/stb_truetype_wasm.o b/vendor/stb/lib/stb_truetype_wasm.o
index 15c4fa0d5..e545ef8e7 100644
--- a/vendor/stb/lib/stb_truetype_wasm.o
+++ b/vendor/stb/lib/stb_truetype_wasm.o
Binary files differ
diff --git a/vendor/stb/rect_pack/stb_rect_pack.odin b/vendor/stb/rect_pack/stb_rect_pack.odin
index 6c0b56378..696b9c8c0 100644
--- a/vendor/stb/rect_pack/stb_rect_pack.odin
+++ b/vendor/stb/rect_pack/stb_rect_pack.odin
@@ -9,6 +9,7 @@ LIB :: (
"../lib/stb_rect_pack.lib" when ODIN_OS == .Windows
else "../lib/stb_rect_pack.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_rect_pack.a" when ODIN_OS == .Darwin
+ else "../lib/stb_rect_pack_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -16,7 +17,11 @@ when LIB != "" {
when !#exists(LIB) {
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
+}
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import lib "../lib/stb_rect_pack_wasm.o"
+} else when LIB != "" {
foreign import lib { LIB }
} else {
foreign import lib "system:stb_rect_pack"
diff --git a/vendor/stb/rect_pack/stb_rect_pack_wasm.odin b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin
new file mode 100644
index 000000000..c4e2e5160
--- /dev/null
+++ b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin
@@ -0,0 +1,4 @@
+#+build wasm32, wasm64p32
+package stb_rect_pack
+
+@(require) import _ "vendor:libc"
diff --git a/vendor/stb/sprintf/stb_sprintf.odin b/vendor/stb/sprintf/stb_sprintf.odin
new file mode 100644
index 000000000..ec5036e45
--- /dev/null
+++ b/vendor/stb/sprintf/stb_sprintf.odin
@@ -0,0 +1,37 @@
+package stb_sprintf
+
+import "core:c"
+
+@(private)
+LIB :: (
+ "../lib/stb_sprintf.lib" when ODIN_OS == .Windows
+ else "../lib/stb_sprintf.a" when ODIN_OS == .Linux
+ else "../lib/darwin/stb_sprintf.a" when ODIN_OS == .Darwin
+ else "../lib/stb_sprintf_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
+ else ""
+)
+
+when LIB != "" {
+ when !#exists(LIB) {
+ #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+ }
+}
+
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+ foreign import stbpf "../lib/stb_sprintf_wasm.o"
+} else when LIB != "" {
+ foreign import stbpf { LIB }
+} else {
+ foreign import stbpf "system:stb_sprintf"
+}
+
+@(link_prefix="stbsp_", default_calling_convention="c")
+foreign stbpf {
+ sprintf :: proc(buf: [^]byte, fmt: cstring, #c_vararg args: ..any) -> i32 ---
+ snprintf :: proc(buf: [^]byte, count: i32, fmt: cstring, #c_vararg args: ..any) -> i32 ---
+ vsprintf :: proc(buf: [^]byte, fmt: cstring, va: c.va_list) -> i32 ---
+ vsnprintf :: proc(buf: [^]byte, count: i32, fmt: cstring, va: ^c.va_list) -> i32 ---
+ vsprintfcb :: proc(callback: SPRINTFCB, user: rawptr, buf: [^]byte, fmt: cstring, va: ^c.va_list) -> i32 ---
+}
+
+SPRINTFCB :: #type proc "c" (buf: [^]byte, user: rawptr, len: i32) -> cstring
diff --git a/vendor/stb/src/Makefile b/vendor/stb/src/Makefile
index 6123a95fa..194ea5e75 100644
--- a/vendor/stb/src/Makefile
+++ b/vendor/stb/src/Makefile
@@ -8,17 +8,24 @@ endif
wasm:
mkdir -p ../lib
- clang -c -Os --target=wasm32 -nostdlib stb_truetype_wasm.c -o ../lib/stb_truetype_wasm.o
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o
+ # $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO
+ $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o
+ $(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_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
+ $(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 stb_sprintf.c
$(AR) rcs ../lib/stb_image.a stb_image.o
$(AR) rcs ../lib/stb_image_write.a stb_image_write.o
$(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o
$(AR) rcs ../lib/stb_truetype.a stb_truetype.o
$(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o
$(AR) rcs ../lib/stb_vorbis.a stb_vorbis.o
+ $(AR) rcs ../lib/stb_sprintf.a stb_sprintf.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o
@@ -47,4 +54,7 @@ darwin:
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-arm64.o -mmacosx-version-min=10.12
lipo -create stb_vorbis-x86_64.o stb_vorbis-arm64.o -output ../lib/darwin/stb_vorbis.a
+ $(CC) -arch x86_64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-x86_64.o -mmacosx-version-min=10.12
+ $(CC) -arch arm64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-arm64.o -mmacosx-version-min=10.12
+ lipo -create stb_sprintf-x86_64.o stb_sprintf-arm64.o -output ../lib/darwin/stb_sprintf.a
rm *.o
diff --git a/vendor/stb/src/stb_sprintf.c b/vendor/stb/src/stb_sprintf.c
new file mode 100644
index 000000000..d60a91bae
--- /dev/null
+++ b/vendor/stb/src/stb_sprintf.c
@@ -0,0 +1,2 @@
+#define STB_SPRINTF_IMPLEMENTATION
+#include "stb_sprintf.h"
diff --git a/vendor/stb/src/stb_sprintf.h b/vendor/stb/src/stb_sprintf.h
new file mode 100644
index 000000000..ca432a6bc
--- /dev/null
+++ b/vendor/stb/src/stb_sprintf.h
@@ -0,0 +1,1906 @@
+// stb_sprintf - v1.10 - public domain snprintf() implementation
+// originally by Jeff Roberts / RAD Game Tools, 2015/10/20
+// http://github.com/nothings/stb
+//
+// allowed types: sc uidBboXx p AaGgEef n
+// lengths : hh h ll j z t I64 I32 I
+//
+// Contributors:
+// Fabian "ryg" Giesen (reformatting)
+// github:aganm (attribute format)
+//
+// Contributors (bugfixes):
+// github:d26435
+// github:trex78
+// github:account-login
+// Jari Komppa (SI suffixes)
+// Rohit Nirmal
+// Marcin Wojdyr
+// Leonard Ritter
+// Stefano Zanotti
+// Adam Allison
+// Arvid Gerstmann
+// Markus Kolb
+//
+// LICENSE:
+//
+// See end of file for license information.
+
+#ifndef STB_SPRINTF_H_INCLUDE
+#define STB_SPRINTF_H_INCLUDE
+
+/*
+Single file sprintf replacement.
+
+Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20.
+Hereby placed in public domain.
+
+This is a full sprintf replacement that supports everything that
+the C runtime sprintfs support, including float/double, 64-bit integers,
+hex floats, field parameters (%*.*d stuff), length reads backs, etc.
+
+Why would you need this if sprintf already exists? Well, first off,
+it's *much* faster (see below). It's also much smaller than the CRT
+versions code-space-wise. We've also added some simple improvements
+that are super handy (commas in thousands, callbacks at buffer full,
+for example). Finally, the format strings for MSVC and GCC differ
+for 64-bit integers (among other small things), so this lets you use
+the same format strings in cross platform code.
+
+It uses the standard single file trick of being both the header file
+and the source itself. If you just include it normally, you just get
+the header file function definitions. To get the code, you include
+it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.
+
+It only uses va_args macros from the C runtime to do it's work. It
+does cast doubles to S64s and shifts and divides U64s, which does
+drag in CRT code on most platforms.
+
+It compiles to roughly 8K with float support, and 4K without.
+As a comparison, when using MSVC static libs, calling sprintf drags
+in 16K.
+
+API:
+====
+int stbsp_sprintf( char * buf, char const * fmt, ... )
+int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
+ Convert an arg list into a buffer. stbsp_snprintf always returns
+ a zero-terminated string (unlike regular snprintf).
+
+int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
+int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
+ Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns
+ a zero-terminated string (unlike regular snprintf).
+
+int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
+ typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
+ Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
+ Your callback can then copy the chars out, print them or whatever.
+ This function is actually the workhorse for everything else.
+ The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
+ // you return the next buffer to use or 0 to stop converting
+
+void stbsp_set_separators( char comma, char period )
+ Set the comma and period characters to use.
+
+FLOATS/DOUBLES:
+===============
+This code uses a internal float->ascii conversion method that uses
+doubles with error correction (double-doubles, for ~105 bits of
+precision). This conversion is round-trip perfect - that is, an atof
+of the values output here will give you the bit-exact double back.
+
+One difference is that our insignificant digits will be different than
+with MSVC or GCC (but they don't match each other either). We also
+don't attempt to find the minimum length matching float (pre-MSVC15
+doesn't either).
+
+If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
+and you'll save 4K of code space.
+
+64-BIT INTS:
+============
+This library also supports 64-bit integers and you can use MSVC style or
+GCC style indicators (%I64d or %lld). It supports the C99 specifiers
+for size_t and ptr_diff_t (%jd %zd) as well.
+
+EXTRAS:
+=======
+Like some GCCs, for integers and floats, you can use a ' (single quote)
+specifier and commas will be inserted on the thousands: "%'d" on 12345
+would print 12,345.
+
+For integers and floats, you can use a "$" specifier and the number
+will be converted to float and then divided to get kilo, mega, giga or
+tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
+"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
+2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
+$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
+suffix, add "_" specifier: "%_$d" -> "2.53M".
+
+In addition to octal and hexadecimal conversions, you can print
+integers in binary: "%b" for 256 would print 100.
+
+PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
+===================================================================
+"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
+"%24d" across all 32-bit ints (4.5x/4.2x faster)
+"%x" across all 32-bit ints (4.5x/3.8x faster)
+"%08x" across all 32-bit ints (4.3x/3.8x faster)
+"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
+"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
+"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
+"%f" for values near e-300 (7.9x/6.5x faster)
+"%f" for values near e+300 (10.0x/9.1x faster)
+"%e" for values near e-300 (10.1x/7.0x faster)
+"%e" for values near e+300 (9.2x/6.0x faster)
+"%.320f" for values near e-300 (12.6x/11.2x faster)
+"%a" for random values (8.6x/4.3x faster)
+"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
+"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
+"%s%s%s" for 64 char strings (7.1x/7.3x faster)
+"...512 char string..." ( 35.0x/32.5x faster!)
+*/
+
+#if defined(__clang__)
+ #if defined(__has_feature) && defined(__has_attribute)
+ #if __has_feature(address_sanitizer)
+ #if __has_attribute(__no_sanitize__)
+ #define STBSP__ASAN __attribute__((__no_sanitize__("address")))
+ #elif __has_attribute(__no_sanitize_address__)
+ #define STBSP__ASAN __attribute__((__no_sanitize_address__))
+ #elif __has_attribute(__no_address_safety_analysis__)
+ #define STBSP__ASAN __attribute__((__no_address_safety_analysis__))
+ #endif
+ #endif
+ #endif
+#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
+ #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__
+ #define STBSP__ASAN __attribute__((__no_sanitize_address__))
+ #endif
+#endif
+
+#ifndef STBSP__ASAN
+#define STBSP__ASAN
+#endif
+
+#ifdef STB_SPRINTF_STATIC
+#define STBSP__PUBLICDEC static
+#define STBSP__PUBLICDEF static STBSP__ASAN
+#else
+#ifdef __cplusplus
+#define STBSP__PUBLICDEC extern "C"
+#define STBSP__PUBLICDEF extern "C" STBSP__ASAN
+#else
+#define STBSP__PUBLICDEC extern
+#define STBSP__PUBLICDEF STBSP__ASAN
+#endif
+#endif
+
+#if defined(__has_attribute)
+ #if __has_attribute(format)
+ #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va)))
+ #endif
+#endif
+
+#ifndef STBSP__ATTRIBUTE_FORMAT
+#define STBSP__ATTRIBUTE_FORMAT(fmt,va)
+#endif
+
+#ifdef _MSC_VER
+#define STBSP__NOTUSED(v) (void)(v)
+#else
+#define STBSP__NOTUSED(v) (void)sizeof(v)
+#endif
+
+#include <stdarg.h> // for va_arg(), va_list()
+#include <stddef.h> // size_t, ptrdiff_t
+
+#ifndef STB_SPRINTF_MIN
+#define STB_SPRINTF_MIN 512 // how many characters per callback
+#endif
+typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len);
+
+#ifndef STB_SPRINTF_DECORATE
+#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
+#endif
+
+STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
+STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
+STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
+STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4);
+
+STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
+STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
+
+#endif // STB_SPRINTF_H_INCLUDE
+
+#ifdef STB_SPRINTF_IMPLEMENTATION
+
+#define stbsp__uint32 unsigned int
+#define stbsp__int32 signed int
+
+#ifdef _MSC_VER
+#define stbsp__uint64 unsigned __int64
+#define stbsp__int64 signed __int64
+#else
+#define stbsp__uint64 unsigned long long
+#define stbsp__int64 signed long long
+#endif
+#define stbsp__uint16 unsigned short
+
+#ifndef stbsp__uintptr
+#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__)
+#define stbsp__uintptr stbsp__uint64
+#else
+#define stbsp__uintptr stbsp__uint32
+#endif
+#endif
+
+#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC)
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define STB_SPRINTF_MSVC_MODE
+#endif
+#endif
+
+#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses
+#define STBSP__UNALIGNED(code)
+#else
+#define STBSP__UNALIGNED(code) code
+#endif
+
+#ifndef STB_SPRINTF_NOFLOAT
+// internal float utility functions
+static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits);
+static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value);
+#define STBSP__SPECIAL 0x7000
+#endif
+
+static char stbsp__period = '.';
+static char stbsp__comma = ',';
+static struct
+{
+ short temp; // force next field to be 2-byte aligned
+ char pair[201];
+} stbsp__digitpair =
+{
+ 0,
+ "00010203040506070809101112131415161718192021222324"
+ "25262728293031323334353637383940414243444546474849"
+ "50515253545556575859606162636465666768697071727374"
+ "75767778798081828384858687888990919293949596979899"
+};
+
+STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod)
+{
+ stbsp__period = pperiod;
+ stbsp__comma = pcomma;
+}
+
+#define STBSP__LEFTJUST 1
+#define STBSP__LEADINGPLUS 2
+#define STBSP__LEADINGSPACE 4
+#define STBSP__LEADING_0X 8
+#define STBSP__LEADINGZERO 16
+#define STBSP__INTMAX 32
+#define STBSP__TRIPLET_COMMA 64
+#define STBSP__NEGATIVE 128
+#define STBSP__METRIC_SUFFIX 256
+#define STBSP__HALFWIDTH 512
+#define STBSP__METRIC_NOSPACE 1024
+#define STBSP__METRIC_1024 2048
+#define STBSP__METRIC_JEDEC 4096
+
+static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
+{
+ sign[0] = 0;
+ if (fl & STBSP__NEGATIVE) {
+ sign[0] = 1;
+ sign[1] = '-';
+ } else if (fl & STBSP__LEADINGSPACE) {
+ sign[0] = 1;
+ sign[1] = ' ';
+ } else if (fl & STBSP__LEADINGPLUS) {
+ sign[0] = 1;
+ sign[1] = '+';
+ }
+}
+
+static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit)
+{
+ char const * sn = s;
+
+ // get up to 4-byte alignment
+ for (;;) {
+ if (((stbsp__uintptr)sn & 3) == 0)
+ break;
+
+ if (!limit || *sn == 0)
+ return (stbsp__uint32)(sn - s);
+
+ ++sn;
+ --limit;
+ }
+
+ // scan over 4 bytes at a time to find terminating 0
+ // this will intentionally scan up to 3 bytes past the end of buffers,
+ // but becase it works 4B aligned, it will never cross page boundaries
+ // (hence the STBSP__ASAN markup; the over-read here is intentional
+ // and harmless)
+ while (limit >= 4) {
+ stbsp__uint32 v = *(stbsp__uint32 *)sn;
+ // bit hack to find if there's a 0 byte in there
+ if ((v - 0x01010101) & (~v) & 0x80808080UL)
+ break;
+
+ sn += 4;
+ limit -= 4;
+ }
+
+ // handle the last few characters to find actual size
+ while (limit && *sn) {
+ ++sn;
+ --limit;
+ }
+
+ return (stbsp__uint32)(sn - s);
+}
+
+STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
+{
+ static char hex[] = "0123456789abcdefxp";
+ static char hexu[] = "0123456789ABCDEFXP";
+ char *bf;
+ char const *f;
+ int tlen = 0;
+
+ bf = buf;
+ f = fmt;
+ for (;;) {
+ stbsp__int32 fw, pr, tz;
+ stbsp__uint32 fl;
+
+ // macros for the callback buffer stuff
+ #define stbsp__chk_cb_bufL(bytes) \
+ { \
+ int len = (int)(bf - buf); \
+ if ((len + (bytes)) >= STB_SPRINTF_MIN) { \
+ tlen += len; \
+ if (0 == (bf = buf = callback(buf, user, len))) \
+ goto done; \
+ } \
+ }
+ #define stbsp__chk_cb_buf(bytes) \
+ { \
+ if (callback) { \
+ stbsp__chk_cb_bufL(bytes); \
+ } \
+ }
+ #define stbsp__flush_cb() \
+ { \
+ stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \
+ } // flush if there is even one byte in the buffer
+ #define stbsp__cb_buf_clamp(cl, v) \
+ cl = v; \
+ if (callback) { \
+ int lg = STB_SPRINTF_MIN - (int)(bf - buf); \
+ if (cl > lg) \
+ cl = lg; \
+ }
+
+ // fast copy everything up to the next % (or end of string)
+ for (;;) {
+ while (((stbsp__uintptr)f) & 3) {
+ schk1:
+ if (f[0] == '%')
+ goto scandd;
+ schk2:
+ if (f[0] == 0)
+ goto endfmt;
+ stbsp__chk_cb_buf(1);
+ *bf++ = f[0];
+ ++f;
+ }
+ for (;;) {
+ // Check if the next 4 bytes contain %(0x25) or end of string.
+ // Using the 'hasless' trick:
+ // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
+ stbsp__uint32 v, c;
+ v = *(stbsp__uint32 *)f;
+ c = (~v) & 0x80808080;
+ if (((v ^ 0x25252525) - 0x01010101) & c)
+ goto schk1;
+ if ((v - 0x01010101) & c)
+ goto schk2;
+ if (callback)
+ if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4)
+ goto schk1;
+ #ifdef STB_SPRINTF_NOUNALIGNED
+ if(((stbsp__uintptr)bf) & 3) {
+ bf[0] = f[0];
+ bf[1] = f[1];
+ bf[2] = f[2];
+ bf[3] = f[3];
+ } else
+ #endif
+ {
+ *(stbsp__uint32 *)bf = v;
+ }
+ bf += 4;
+ f += 4;
+ }
+ }
+ scandd:
+
+ ++f;
+
+ // ok, we have a percent, read the modifiers first
+ fw = 0;
+ pr = -1;
+ fl = 0;
+ tz = 0;
+
+ // flags
+ for (;;) {
+ switch (f[0]) {
+ // if we have left justify
+ case '-':
+ fl |= STBSP__LEFTJUST;
+ ++f;
+ continue;
+ // if we have leading plus
+ case '+':
+ fl |= STBSP__LEADINGPLUS;
+ ++f;
+ continue;
+ // if we have leading space
+ case ' ':
+ fl |= STBSP__LEADINGSPACE;
+ ++f;
+ continue;
+ // if we have leading 0x
+ case '#':
+ fl |= STBSP__LEADING_0X;
+ ++f;
+ continue;
+ // if we have thousand commas
+ case '\'':
+ fl |= STBSP__TRIPLET_COMMA;
+ ++f;
+ continue;
+ // if we have kilo marker (none->kilo->kibi->jedec)
+ case '$':
+ if (fl & STBSP__METRIC_SUFFIX) {
+ if (fl & STBSP__METRIC_1024) {
+ fl |= STBSP__METRIC_JEDEC;
+ } else {
+ fl |= STBSP__METRIC_1024;
+ }
+ } else {
+ fl |= STBSP__METRIC_SUFFIX;
+ }
+ ++f;
+ continue;
+ // if we don't want space between metric suffix and number
+ case '_':
+ fl |= STBSP__METRIC_NOSPACE;
+ ++f;
+ continue;
+ // if we have leading zero
+ case '0':
+ fl |= STBSP__LEADINGZERO;
+ ++f;
+ goto flags_done;
+ default: goto flags_done;
+ }
+ }
+ flags_done:
+
+ // get the field width
+ if (f[0] == '*') {
+ fw = va_arg(va, stbsp__uint32);
+ ++f;
+ } else {
+ while ((f[0] >= '0') && (f[0] <= '9')) {
+ fw = fw * 10 + f[0] - '0';
+ f++;
+ }
+ }
+ // get the precision
+ if (f[0] == '.') {
+ ++f;
+ if (f[0] == '*') {
+ pr = va_arg(va, stbsp__uint32);
+ ++f;
+ } else {
+ pr = 0;
+ while ((f[0] >= '0') && (f[0] <= '9')) {
+ pr = pr * 10 + f[0] - '0';
+ f++;
+ }
+ }
+ }
+
+ // handle integer size overrides
+ switch (f[0]) {
+ // are we halfwidth?
+ case 'h':
+ fl |= STBSP__HALFWIDTH;
+ ++f;
+ if (f[0] == 'h')
+ ++f; // QUARTERWIDTH
+ break;
+ // are we 64-bit (unix style)
+ case 'l':
+ fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0);
+ ++f;
+ if (f[0] == 'l') {
+ fl |= STBSP__INTMAX;
+ ++f;
+ }
+ break;
+ // are we 64-bit on intmax? (c99)
+ case 'j':
+ fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0;
+ ++f;
+ break;
+ // are we 64-bit on size_t or ptrdiff_t? (c99)
+ case 'z':
+ fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
+ ++f;
+ break;
+ case 't':
+ fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0;
+ ++f;
+ break;
+ // are we 64-bit (msft style)
+ case 'I':
+ if ((f[1] == '6') && (f[2] == '4')) {
+ fl |= STBSP__INTMAX;
+ f += 3;
+ } else if ((f[1] == '3') && (f[2] == '2')) {
+ f += 3;
+ } else {
+ fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0);
+ ++f;
+ }
+ break;
+ default: break;
+ }
+
+ // handle each replacement
+ switch (f[0]) {
+ #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307
+ char num[STBSP__NUMSZ];
+ char lead[8];
+ char tail[8];
+ char *s;
+ char const *h;
+ stbsp__uint32 l, n, cs;
+ stbsp__uint64 n64;
+#ifndef STB_SPRINTF_NOFLOAT
+ double fv;
+#endif
+ stbsp__int32 dp;
+ char const *sn;
+
+ case 's':
+ // get the string
+ s = va_arg(va, char *);
+ if (s == 0)
+ s = (char *)"null";
+ // get the length, limited to desired precision
+ // always limit to ~0u chars since our counts are 32b
+ l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u);
+ lead[0] = 0;
+ tail[0] = 0;
+ pr = 0;
+ dp = 0;
+ cs = 0;
+ // copy the string in
+ goto scopy;
+
+ case 'c': // char
+ // get the character
+ s = num + STBSP__NUMSZ - 1;
+ *s = (char)va_arg(va, int);
+ l = 1;
+ lead[0] = 0;
+ tail[0] = 0;
+ pr = 0;
+ dp = 0;
+ cs = 0;
+ goto scopy;
+
+ case 'n': // weird write-bytes specifier
+ {
+ int *d = va_arg(va, int *);
+ *d = tlen + (int)(bf - buf);
+ } break;
+
+#ifdef STB_SPRINTF_NOFLOAT
+ case 'A': // float
+ case 'a': // hex float
+ case 'G': // float
+ case 'g': // float
+ case 'E': // float
+ case 'e': // float
+ case 'f': // float
+ va_arg(va, double); // eat it
+ s = (char *)"No float";
+ l = 8;
+ lead[0] = 0;
+ tail[0] = 0;
+ pr = 0;
+ cs = 0;
+ STBSP__NOTUSED(dp);
+ goto scopy;
+#else
+ case 'A': // hex float
+ case 'a': // hex float
+ h = (f[0] == 'A') ? hexu : hex;
+ fv = va_arg(va, double);
+ if (pr == -1)
+ pr = 6; // default is 6
+ // read the double into a string
+ if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv))
+ fl |= STBSP__NEGATIVE;
+
+ s = num + 64;
+
+ stbsp__lead_sign(fl, lead);
+
+ if (dp == -1023)
+ dp = (n64) ? -1022 : 0;
+ else
+ n64 |= (((stbsp__uint64)1) << 52);
+ n64 <<= (64 - 56);
+ if (pr < 15)
+ n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4));
+// add leading chars
+
+#ifdef STB_SPRINTF_MSVC_MODE
+ *s++ = '0';
+ *s++ = 'x';
+#else
+ lead[1 + lead[0]] = '0';
+ lead[2 + lead[0]] = 'x';
+ lead[0] += 2;
+#endif
+ *s++ = h[(n64 >> 60) & 15];
+ n64 <<= 4;
+ if (pr)
+ *s++ = stbsp__period;
+ sn = s;
+
+ // print the bits
+ n = pr;
+ if (n > 13)
+ n = 13;
+ if (pr > (stbsp__int32)n)
+ tz = pr - n;
+ pr = 0;
+ while (n--) {
+ *s++ = h[(n64 >> 60) & 15];
+ n64 <<= 4;
+ }
+
+ // print the expo
+ tail[1] = h[17];
+ if (dp < 0) {
+ tail[2] = '-';
+ dp = -dp;
+ } else
+ tail[2] = '+';
+ n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3));
+ tail[0] = (char)n;
+ for (;;) {
+ tail[n] = '0' + dp % 10;
+ if (n <= 3)
+ break;
+ --n;
+ dp /= 10;
+ }
+
+ dp = (int)(s - sn);
+ l = (int)(s - (num + 64));
+ s = num + 64;
+ cs = 1 + (3 << 24);
+ goto scopy;
+
+ case 'G': // float
+ case 'g': // float
+ h = (f[0] == 'G') ? hexu : hex;
+ fv = va_arg(va, double);
+ if (pr == -1)
+ pr = 6;
+ else if (pr == 0)
+ pr = 1; // default is 6
+ // read the double into a string
+ if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000))
+ fl |= STBSP__NEGATIVE;
+
+ // clamp the precision and delete extra zeros after clamp
+ n = pr;
+ if (l > (stbsp__uint32)pr)
+ l = pr;
+ while ((l > 1) && (pr) && (sn[l - 1] == '0')) {
+ --pr;
+ --l;
+ }
+
+ // should we use %e
+ if ((dp <= -4) || (dp > (stbsp__int32)n)) {
+ if (pr > (stbsp__int32)l)
+ pr = l - 1;
+ else if (pr)
+ --pr; // when using %e, there is one digit before the decimal
+ goto doexpfromg;
+ }
+ // this is the insane action to get the pr to match %g semantics for %f
+ if (dp > 0) {
+ pr = (dp < (stbsp__int32)l) ? l - dp : 0;
+ } else {
+ pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr);
+ }
+ goto dofloatfromg;
+
+ case 'E': // float
+ case 'e': // float
+ h = (f[0] == 'E') ? hexu : hex;
+ fv = va_arg(va, double);
+ if (pr == -1)
+ pr = 6; // default is 6
+ // read the double into a string
+ if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000))
+ fl |= STBSP__NEGATIVE;
+ doexpfromg:
+ tail[0] = 0;
+ stbsp__lead_sign(fl, lead);
+ if (dp == STBSP__SPECIAL) {
+ s = (char *)sn;
+ cs = 0;
+ pr = 0;
+ goto scopy;
+ }
+ s = num + 64;
+ // handle leading chars
+ *s++ = sn[0];
+
+ if (pr)
+ *s++ = stbsp__period;
+
+ // handle after decimal
+ if ((l - 1) > (stbsp__uint32)pr)
+ l = pr + 1;
+ for (n = 1; n < l; n++)
+ *s++ = sn[n];
+ // trailing zeros
+ tz = pr - (l - 1);
+ pr = 0;
+ // dump expo
+ tail[1] = h[0xe];
+ dp -= 1;
+ if (dp < 0) {
+ tail[2] = '-';
+ dp = -dp;
+ } else
+ tail[2] = '+';
+#ifdef STB_SPRINTF_MSVC_MODE
+ n = 5;
+#else
+ n = (dp >= 100) ? 5 : 4;
+#endif
+ tail[0] = (char)n;
+ for (;;) {
+ tail[n] = '0' + dp % 10;
+ if (n <= 3)
+ break;
+ --n;
+ dp /= 10;
+ }
+ cs = 1 + (3 << 24); // how many tens
+ goto flt_lead;
+
+ case 'f': // float
+ fv = va_arg(va, double);
+ doafloat:
+ // do kilos
+ if (fl & STBSP__METRIC_SUFFIX) {
+ double divisor;
+ divisor = 1000.0f;
+ if (fl & STBSP__METRIC_1024)
+ divisor = 1024.0;
+ while (fl < 0x4000000) {
+ if ((fv < divisor) && (fv > -divisor))
+ break;
+ fv /= divisor;
+ fl += 0x1000000;
+ }
+ }
+ if (pr == -1)
+ pr = 6; // default is 6
+ // read the double into a string
+ if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr))
+ fl |= STBSP__NEGATIVE;
+ dofloatfromg:
+ tail[0] = 0;
+ stbsp__lead_sign(fl, lead);
+ if (dp == STBSP__SPECIAL) {
+ s = (char *)sn;
+ cs = 0;
+ pr = 0;
+ goto scopy;
+ }
+ s = num + 64;
+
+ // handle the three decimal varieties
+ if (dp <= 0) {
+ stbsp__int32 i;
+ // handle 0.000*000xxxx
+ *s++ = '0';
+ if (pr)
+ *s++ = stbsp__period;
+ n = -dp;
+ if ((stbsp__int32)n > pr)
+ n = pr;
+ i = n;
+ while (i) {
+ if ((((stbsp__uintptr)s) & 3) == 0)
+ break;
+ *s++ = '0';
+ --i;
+ }
+ while (i >= 4) {
+ *(stbsp__uint32 *)s = 0x30303030;
+ s += 4;
+ i -= 4;
+ }
+ while (i) {
+ *s++ = '0';
+ --i;
+ }
+ if ((stbsp__int32)(l + n) > pr)
+ l = pr - n;
+ i = l;
+ while (i) {
+ *s++ = *sn++;
+ --i;
+ }
+ tz = pr - (n + l);
+ cs = 1 + (3 << 24); // how many tens did we write (for commas below)
+ } else {
+ cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0;
+ if ((stbsp__uint32)dp >= l) {
+ // handle xxxx000*000.0
+ n = 0;
+ for (;;) {
+ if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
+ cs = 0;
+ *s++ = stbsp__comma;
+ } else {
+ *s++ = sn[n];
+ ++n;
+ if (n >= l)
+ break;
+ }
+ }
+ if (n < (stbsp__uint32)dp) {
+ n = dp - n;
+ if ((fl & STBSP__TRIPLET_COMMA) == 0) {
+ while (n) {
+ if ((((stbsp__uintptr)s) & 3) == 0)
+ break;
+ *s++ = '0';
+ --n;
+ }
+ while (n >= 4) {
+ *(stbsp__uint32 *)s = 0x30303030;
+ s += 4;
+ n -= 4;
+ }
+ }
+ while (n) {
+ if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
+ cs = 0;
+ *s++ = stbsp__comma;
+ } else {
+ *s++ = '0';
+ --n;
+ }
+ }
+ }
+ cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
+ if (pr) {
+ *s++ = stbsp__period;
+ tz = pr;
+ }
+ } else {
+ // handle xxxxx.xxxx000*000
+ n = 0;
+ for (;;) {
+ if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) {
+ cs = 0;
+ *s++ = stbsp__comma;
+ } else {
+ *s++ = sn[n];
+ ++n;
+ if (n >= (stbsp__uint32)dp)
+ break;
+ }
+ }
+ cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens
+ if (pr)
+ *s++ = stbsp__period;
+ if ((l - dp) > (stbsp__uint32)pr)
+ l = pr + dp;
+ while (n < l) {
+ *s++ = sn[n];
+ ++n;
+ }
+ tz = pr - (l - dp);
+ }
+ }
+ pr = 0;
+
+ // handle k,m,g,t
+ if (fl & STBSP__METRIC_SUFFIX) {
+ char idx;
+ idx = 1;
+ if (fl & STBSP__METRIC_NOSPACE)
+ idx = 0;
+ tail[0] = idx;
+ tail[1] = ' ';
+ {
+ if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'.
+ if (fl & STBSP__METRIC_1024)
+ tail[idx + 1] = "_KMGT"[fl >> 24];
+ else
+ tail[idx + 1] = "_kMGT"[fl >> 24];
+ idx++;
+ // If printing kibits and not in jedec, add the 'i'.
+ if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) {
+ tail[idx + 1] = 'i';
+ idx++;
+ }
+ tail[0] = idx;
+ }
+ }
+ };
+
+ flt_lead:
+ // get the length that we copied
+ l = (stbsp__uint32)(s - (num + 64));
+ s = num + 64;
+ goto scopy;
+#endif
+
+ case 'B': // upper binary
+ case 'b': // lower binary
+ h = (f[0] == 'B') ? hexu : hex;
+ lead[0] = 0;
+ if (fl & STBSP__LEADING_0X) {
+ lead[0] = 2;
+ lead[1] = '0';
+ lead[2] = h[0xb];
+ }
+ l = (8 << 4) | (1 << 8);
+ goto radixnum;
+
+ case 'o': // octal
+ h = hexu;
+ lead[0] = 0;
+ if (fl & STBSP__LEADING_0X) {
+ lead[0] = 1;
+ lead[1] = '0';
+ }
+ l = (3 << 4) | (3 << 8);
+ goto radixnum;
+
+ case 'p': // pointer
+ fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0;
+ pr = sizeof(void *) * 2;
+ fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros
+ // fall through - to X
+
+ case 'X': // upper hex
+ case 'x': // lower hex
+ h = (f[0] == 'X') ? hexu : hex;
+ l = (4 << 4) | (4 << 8);
+ lead[0] = 0;
+ if (fl & STBSP__LEADING_0X) {
+ lead[0] = 2;
+ lead[1] = '0';
+ lead[2] = h[16];
+ }
+ radixnum:
+ // get the number
+ if (fl & STBSP__INTMAX)
+ n64 = va_arg(va, stbsp__uint64);
+ else
+ n64 = va_arg(va, stbsp__uint32);
+
+ s = num + STBSP__NUMSZ;
+ dp = 0;
+ // clear tail, and clear leading if value is zero
+ tail[0] = 0;
+ if (n64 == 0) {
+ lead[0] = 0;
+ if (pr == 0) {
+ l = 0;
+ cs = 0;
+ goto scopy;
+ }
+ }
+ // convert to string
+ for (;;) {
+ *--s = h[n64 & ((1 << (l >> 8)) - 1)];
+ n64 >>= (l >> 8);
+ if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr)))
+ break;
+ if (fl & STBSP__TRIPLET_COMMA) {
+ ++l;
+ if ((l & 15) == ((l >> 4) & 15)) {
+ l &= ~15;
+ *--s = stbsp__comma;
+ }
+ }
+ };
+ // get the tens and the comma pos
+ cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24);
+ // get the length that we copied
+ l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
+ // copy it
+ goto scopy;
+
+ case 'u': // unsigned
+ case 'i':
+ case 'd': // integer
+ // get the integer and abs it
+ if (fl & STBSP__INTMAX) {
+ stbsp__int64 i64 = va_arg(va, stbsp__int64);
+ n64 = (stbsp__uint64)i64;
+ if ((f[0] != 'u') && (i64 < 0)) {
+ n64 = (stbsp__uint64)-i64;
+ fl |= STBSP__NEGATIVE;
+ }
+ } else {
+ stbsp__int32 i = va_arg(va, stbsp__int32);
+ n64 = (stbsp__uint32)i;
+ if ((f[0] != 'u') && (i < 0)) {
+ n64 = (stbsp__uint32)-i;
+ fl |= STBSP__NEGATIVE;
+ }
+ }
+
+#ifndef STB_SPRINTF_NOFLOAT
+ if (fl & STBSP__METRIC_SUFFIX) {
+ if (n64 < 1024)
+ pr = 0;
+ else if (pr == -1)
+ pr = 1;
+ fv = (double)(stbsp__int64)n64;
+ goto doafloat;
+ }
+#endif
+
+ // convert to string
+ s = num + STBSP__NUMSZ;
+ l = 0;
+
+ for (;;) {
+ // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators)
+ char *o = s - 8;
+ if (n64 >= 100000000) {
+ n = (stbsp__uint32)(n64 % 100000000);
+ n64 /= 100000000;
+ } else {
+ n = (stbsp__uint32)n64;
+ n64 = 0;
+ }
+ if ((fl & STBSP__TRIPLET_COMMA) == 0) {
+ do {
+ s -= 2;
+ *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
+ n /= 100;
+ } while (n);
+ }
+ while (n) {
+ if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
+ l = 0;
+ *--s = stbsp__comma;
+ --o;
+ } else {
+ *--s = (char)(n % 10) + '0';
+ n /= 10;
+ }
+ }
+ if (n64 == 0) {
+ if ((s[0] == '0') && (s != (num + STBSP__NUMSZ)))
+ ++s;
+ break;
+ }
+ while (s != o)
+ if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) {
+ l = 0;
+ *--s = stbsp__comma;
+ --o;
+ } else {
+ *--s = '0';
+ }
+ }
+
+ tail[0] = 0;
+ stbsp__lead_sign(fl, lead);
+
+ // get the length that we copied
+ l = (stbsp__uint32)((num + STBSP__NUMSZ) - s);
+ if (l == 0) {
+ *--s = '0';
+ l = 1;
+ }
+ cs = l + (3 << 24);
+ if (pr < 0)
+ pr = 0;
+
+ scopy:
+ // get fw=leading/trailing space, pr=leading zeros
+ if (pr < (stbsp__int32)l)
+ pr = l;
+ n = pr + lead[0] + tail[0] + tz;
+ if (fw < (stbsp__int32)n)
+ fw = n;
+ fw -= n;
+ pr -= l;
+
+ // handle right justify and leading zeros
+ if ((fl & STBSP__LEFTJUST) == 0) {
+ if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr
+ {
+ pr = (fw > pr) ? fw : pr;
+ fw = 0;
+ } else {
+ fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas
+ }
+ }
+
+ // copy the spaces and/or zeros
+ if (fw + pr) {
+ stbsp__int32 i;
+ stbsp__uint32 c;
+
+ // copy leading spaces (or when doing %8.4d stuff)
+ if ((fl & STBSP__LEFTJUST) == 0)
+ while (fw > 0) {
+ stbsp__cb_buf_clamp(i, fw);
+ fw -= i;
+ while (i) {
+ if ((((stbsp__uintptr)bf) & 3) == 0)
+ break;
+ *bf++ = ' ';
+ --i;
+ }
+ while (i >= 4) {
+ *(stbsp__uint32 *)bf = 0x20202020;
+ bf += 4;
+ i -= 4;
+ }
+ while (i) {
+ *bf++ = ' ';
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // copy leader
+ sn = lead + 1;
+ while (lead[0]) {
+ stbsp__cb_buf_clamp(i, lead[0]);
+ lead[0] -= (char)i;
+ while (i) {
+ *bf++ = *sn++;
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // copy leading zeros
+ c = cs >> 24;
+ cs &= 0xffffff;
+ cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0;
+ while (pr > 0) {
+ stbsp__cb_buf_clamp(i, pr);
+ pr -= i;
+ if ((fl & STBSP__TRIPLET_COMMA) == 0) {
+ while (i) {
+ if ((((stbsp__uintptr)bf) & 3) == 0)
+ break;
+ *bf++ = '0';
+ --i;
+ }
+ while (i >= 4) {
+ *(stbsp__uint32 *)bf = 0x30303030;
+ bf += 4;
+ i -= 4;
+ }
+ }
+ while (i) {
+ if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) {
+ cs = 0;
+ *bf++ = stbsp__comma;
+ } else
+ *bf++ = '0';
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+ }
+
+ // copy leader if there is still one
+ sn = lead + 1;
+ while (lead[0]) {
+ stbsp__int32 i;
+ stbsp__cb_buf_clamp(i, lead[0]);
+ lead[0] -= (char)i;
+ while (i) {
+ *bf++ = *sn++;
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // copy the string
+ n = l;
+ while (n) {
+ stbsp__int32 i;
+ stbsp__cb_buf_clamp(i, n);
+ n -= i;
+ STBSP__UNALIGNED(while (i >= 4) {
+ *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s;
+ bf += 4;
+ s += 4;
+ i -= 4;
+ })
+ while (i) {
+ *bf++ = *s++;
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // copy trailing zeros
+ while (tz) {
+ stbsp__int32 i;
+ stbsp__cb_buf_clamp(i, tz);
+ tz -= i;
+ while (i) {
+ if ((((stbsp__uintptr)bf) & 3) == 0)
+ break;
+ *bf++ = '0';
+ --i;
+ }
+ while (i >= 4) {
+ *(stbsp__uint32 *)bf = 0x30303030;
+ bf += 4;
+ i -= 4;
+ }
+ while (i) {
+ *bf++ = '0';
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // copy tail if there is one
+ sn = tail + 1;
+ while (tail[0]) {
+ stbsp__int32 i;
+ stbsp__cb_buf_clamp(i, tail[0]);
+ tail[0] -= (char)i;
+ while (i) {
+ *bf++ = *sn++;
+ --i;
+ }
+ stbsp__chk_cb_buf(1);
+ }
+
+ // handle the left justify
+ if (fl & STBSP__LEFTJUST)
+ if (fw > 0) {
+ while (fw) {
+ stbsp__int32 i;
+ stbsp__cb_buf_clamp(i, fw);
+ fw -= i;
+ while (i) {
+ if ((((stbsp__uintptr)bf) & 3) == 0)
+ break;
+ *bf++ = ' ';
+ --i;
+ }
+ while (i >= 4) {
+ *(stbsp__uint32 *)bf = 0x20202020;
+ bf += 4;
+ i -= 4;
+ }
+ while (i--)
+ *bf++ = ' ';
+ stbsp__chk_cb_buf(1);
+ }
+ }
+ break;
+
+ default: // unknown, just copy code
+ s = num + STBSP__NUMSZ - 1;
+ *s = f[0];
+ l = 1;
+ fw = fl = 0;
+ lead[0] = 0;
+ tail[0] = 0;
+ pr = 0;
+ dp = 0;
+ cs = 0;
+ goto scopy;
+ }
+ ++f;
+ }
+endfmt:
+
+ if (!callback)
+ *bf = 0;
+ else
+ stbsp__flush_cb();
+
+done:
+ return tlen + (int)(bf - buf);
+}
+
+// cleanup
+#undef STBSP__LEFTJUST
+#undef STBSP__LEADINGPLUS
+#undef STBSP__LEADINGSPACE
+#undef STBSP__LEADING_0X
+#undef STBSP__LEADINGZERO
+#undef STBSP__INTMAX
+#undef STBSP__TRIPLET_COMMA
+#undef STBSP__NEGATIVE
+#undef STBSP__METRIC_SUFFIX
+#undef STBSP__NUMSZ
+#undef stbsp__chk_cb_bufL
+#undef stbsp__chk_cb_buf
+#undef stbsp__flush_cb
+#undef stbsp__cb_buf_clamp
+
+// ============================================================================
+// wrapper functions
+
+STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...)
+{
+ int result;
+ va_list va;
+ va_start(va, fmt);
+ result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
+ va_end(va);
+ return result;
+}
+
+typedef struct stbsp__context {
+ char *buf;
+ int count;
+ int length;
+ char tmp[STB_SPRINTF_MIN];
+} stbsp__context;
+
+static char *stbsp__clamp_callback(const char *buf, void *user, int len)
+{
+ stbsp__context *c = (stbsp__context *)user;
+ c->length += len;
+
+ if (len > c->count)
+ len = c->count;
+
+ if (len) {
+ if (buf != c->buf) {
+ const char *s, *se;
+ char *d;
+ d = c->buf;
+ s = buf;
+ se = buf + len;
+ do {
+ *d++ = *s++;
+ } while (s < se);
+ }
+ c->buf += len;
+ c->count -= len;
+ }
+
+ if (c->count <= 0)
+ return c->tmp;
+ return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can
+}
+
+static char * stbsp__count_clamp_callback( const char * buf, void * user, int len )
+{
+ stbsp__context * c = (stbsp__context*)user;
+ (void) sizeof(buf);
+
+ c->length += len;
+ return c->tmp; // go direct into buffer if you can
+}
+
+STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va )
+{
+ stbsp__context c;
+
+ if ( (count == 0) && !buf )
+ {
+ c.length = 0;
+
+ STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va );
+ }
+ else
+ {
+ int l;
+
+ c.buf = buf;
+ c.count = count;
+ c.length = 0;
+
+ STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va );
+
+ // zero-terminate
+ l = (int)( c.buf - buf );
+ if ( l >= count ) // should never be greater, only equal (or less) than count
+ l = count - 1;
+ buf[l] = 0;
+ }
+
+ return c.length;
+}
+
+STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...)
+{
+ int result;
+ va_list va;
+ va_start(va, fmt);
+
+ result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va);
+ va_end(va);
+
+ return result;
+}
+
+STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va)
+{
+ return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va);
+}
+
+// =======================================================================
+// low level float utility functions
+
+#ifndef STB_SPRINTF_NOFLOAT
+
+// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox)
+#define STBSP__COPYFP(dest, src) \
+ { \
+ int cn; \
+ for (cn = 0; cn < 8; cn++) \
+ ((char *)&dest)[cn] = ((char *)&src)[cn]; \
+ }
+
+// get float info
+static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value)
+{
+ double d;
+ stbsp__int64 b = 0;
+
+ // load value and round at the frac_digits
+ d = value;
+
+ STBSP__COPYFP(b, d);
+
+ *bits = b & ((((stbsp__uint64)1) << 52) - 1);
+ *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023);
+
+ return (stbsp__int32)((stbsp__uint64) b >> 63);
+}
+
+static double const stbsp__bot[23] = {
+ 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011,
+ 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022
+};
+static double const stbsp__negbot[22] = {
+ 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011,
+ 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022
+};
+static double const stbsp__negboterr[22] = {
+ -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023,
+ 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029,
+ -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035,
+ 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039
+};
+static double const stbsp__top[13] = {
+ 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299
+};
+static double const stbsp__negtop[13] = {
+ 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299
+};
+static double const stbsp__toperr[13] = {
+ 8388608,
+ 6.8601809640529717e+028,
+ -7.253143638152921e+052,
+ -4.3377296974619174e+075,
+ -1.5559416129466825e+098,
+ -3.2841562489204913e+121,
+ -3.7745893248228135e+144,
+ -1.7356668416969134e+167,
+ -3.8893577551088374e+190,
+ -9.9566444326005119e+213,
+ 6.3641293062232429e+236,
+ -5.2069140800249813e+259,
+ -5.2504760255204387e+282
+};
+static double const stbsp__negtoperr[13] = {
+ 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109,
+ -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201,
+ 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293,
+ 8.0970921678014997e-317
+};
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1200)
+static stbsp__uint64 const stbsp__powten[20] = {
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000,
+ 10000000000,
+ 100000000000,
+ 1000000000000,
+ 10000000000000,
+ 100000000000000,
+ 1000000000000000,
+ 10000000000000000,
+ 100000000000000000,
+ 1000000000000000000,
+ 10000000000000000000U
+};
+#define stbsp__tento19th ((stbsp__uint64)1000000000000000000)
+#else
+static stbsp__uint64 const stbsp__powten[20] = {
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000,
+ 10000000000ULL,
+ 100000000000ULL,
+ 1000000000000ULL,
+ 10000000000000ULL,
+ 100000000000000ULL,
+ 1000000000000000ULL,
+ 10000000000000000ULL,
+ 100000000000000000ULL,
+ 1000000000000000000ULL,
+ 10000000000000000000ULL
+};
+#define stbsp__tento19th (1000000000000000000ULL)
+#endif
+
+#define stbsp__ddmulthi(oh, ol, xh, yh) \
+ { \
+ double ahi = 0, alo, bhi = 0, blo; \
+ stbsp__int64 bt; \
+ oh = xh * yh; \
+ STBSP__COPYFP(bt, xh); \
+ bt &= ((~(stbsp__uint64)0) << 27); \
+ STBSP__COPYFP(ahi, bt); \
+ alo = xh - ahi; \
+ STBSP__COPYFP(bt, yh); \
+ bt &= ((~(stbsp__uint64)0) << 27); \
+ STBSP__COPYFP(bhi, bt); \
+ blo = yh - bhi; \
+ ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \
+ }
+
+#define stbsp__ddtoS64(ob, xh, xl) \
+ { \
+ double ahi = 0, alo, vh, t; \
+ ob = (stbsp__int64)xh; \
+ vh = (double)ob; \
+ ahi = (xh - vh); \
+ t = (ahi - xh); \
+ alo = (xh - (ahi - t)) - (vh + t); \
+ ob += (stbsp__int64)(ahi + alo + xl); \
+ }
+
+#define stbsp__ddrenorm(oh, ol) \
+ { \
+ double s; \
+ s = oh + ol; \
+ ol = ol - (s - oh); \
+ oh = s; \
+ }
+
+#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh);
+
+#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl);
+
+static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350
+{
+ double ph, pl;
+ if ((power >= 0) && (power <= 22)) {
+ stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]);
+ } else {
+ stbsp__int32 e, et, eb;
+ double p2h, p2l;
+
+ e = power;
+ if (power < 0)
+ e = -e;
+ et = (e * 0x2c9) >> 14; /* %23 */
+ if (et > 13)
+ et = 13;
+ eb = e - (et * 23);
+
+ ph = d;
+ pl = 0.0;
+ if (power < 0) {
+ if (eb) {
+ --eb;
+ stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]);
+ stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]);
+ }
+ if (et) {
+ stbsp__ddrenorm(ph, pl);
+ --et;
+ stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]);
+ stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]);
+ ph = p2h;
+ pl = p2l;
+ }
+ } else {
+ if (eb) {
+ e = eb;
+ if (eb > 22)
+ eb = 22;
+ e -= eb;
+ stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]);
+ if (e) {
+ stbsp__ddrenorm(ph, pl);
+ stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]);
+ stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl);
+ ph = p2h;
+ pl = p2l;
+ }
+ }
+ if (et) {
+ stbsp__ddrenorm(ph, pl);
+ --et;
+ stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]);
+ stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]);
+ ph = p2h;
+ pl = p2l;
+ }
+ }
+ }
+ stbsp__ddrenorm(ph, pl);
+ *ohi = ph;
+ *olo = pl;
+}
+
+// given a float value, returns the significant bits in bits, and the position of the
+// decimal point in decimal_pos. +/-INF and NAN are specified by special values
+// returned in the decimal_pos parameter.
+// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000
+static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits)
+{
+ double d;
+ stbsp__int64 bits = 0;
+ stbsp__int32 expo, e, ng, tens;
+
+ d = value;
+ STBSP__COPYFP(bits, d);
+ expo = (stbsp__int32)((bits >> 52) & 2047);
+ ng = (stbsp__int32)((stbsp__uint64) bits >> 63);
+ if (ng)
+ d = -d;
+
+ if (expo == 2047) // is nan or inf?
+ {
+ *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf";
+ *decimal_pos = STBSP__SPECIAL;
+ *len = 3;
+ return ng;
+ }
+
+ if (expo == 0) // is zero or denormal
+ {
+ if (((stbsp__uint64) bits << 1) == 0) // do zero
+ {
+ *decimal_pos = 1;
+ *start = out;
+ out[0] = '0';
+ *len = 1;
+ return ng;
+ }
+ // find the right expo for denormals
+ {
+ stbsp__int64 v = ((stbsp__uint64)1) << 51;
+ while ((bits & v) == 0) {
+ --expo;
+ v >>= 1;
+ }
+ }
+ }
+
+ // find the decimal exponent as well as the decimal bits of the value
+ {
+ double ph, pl;
+
+ // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046
+ tens = expo - 1023;
+ tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1);
+
+ // move the significant bits into position and stick them into an int
+ stbsp__raise_to_power10(&ph, &pl, d, 18 - tens);
+
+ // get full as much precision from double-double as possible
+ stbsp__ddtoS64(bits, ph, pl);
+
+ // check if we undershot
+ if (((stbsp__uint64)bits) >= stbsp__tento19th)
+ ++tens;
+ }
+
+ // now do the rounding in integer land
+ frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits);
+ if ((frac_digits < 24)) {
+ stbsp__uint32 dg = 1;
+ if ((stbsp__uint64)bits >= stbsp__powten[9])
+ dg = 10;
+ while ((stbsp__uint64)bits >= stbsp__powten[dg]) {
+ ++dg;
+ if (dg == 20)
+ goto noround;
+ }
+ if (frac_digits < dg) {
+ stbsp__uint64 r;
+ // add 0.5 at the right position and round
+ e = dg - frac_digits;
+ if ((stbsp__uint32)e >= 24)
+ goto noround;
+ r = stbsp__powten[e];
+ bits = bits + (r / 2);
+ if ((stbsp__uint64)bits >= stbsp__powten[dg])
+ ++tens;
+ bits /= r;
+ }
+ noround:;
+ }
+
+ // kill long trailing runs of zeros
+ if (bits) {
+ stbsp__uint32 n;
+ for (;;) {
+ if (bits <= 0xffffffff)
+ break;
+ if (bits % 1000)
+ goto donez;
+ bits /= 1000;
+ }
+ n = (stbsp__uint32)bits;
+ while ((n % 1000) == 0)
+ n /= 1000;
+ bits = n;
+ donez:;
+ }
+
+ // convert to string
+ out += 64;
+ e = 0;
+ for (;;) {
+ stbsp__uint32 n;
+ char *o = out - 8;
+ // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned)
+ if (bits >= 100000000) {
+ n = (stbsp__uint32)(bits % 100000000);
+ bits /= 100000000;
+ } else {
+ n = (stbsp__uint32)bits;
+ bits = 0;
+ }
+ while (n) {
+ out -= 2;
+ *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2];
+ n /= 100;
+ e += 2;
+ }
+ if (bits == 0) {
+ if ((e) && (out[0] == '0')) {
+ ++out;
+ --e;
+ }
+ break;
+ }
+ while (out != o) {
+ *--out = '0';
+ ++e;
+ }
+ }
+
+ *decimal_pos = tens;
+ *start = out;
+ *len = e;
+ return ng;
+}
+
+#undef stbsp__ddmulthi
+#undef stbsp__ddrenorm
+#undef stbsp__ddmultlo
+#undef stbsp__ddmultlos
+#undef STBSP__SPECIAL
+#undef STBSP__COPYFP
+
+#endif // STB_SPRINTF_NOFLOAT
+
+// clean up
+#undef stbsp__uint16
+#undef stbsp__uint32
+#undef stbsp__int32
+#undef stbsp__uint64
+#undef stbsp__int64
+#undef STBSP__UNALIGNED
+
+#endif // STB_SPRINTF_IMPLEMENTATION
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS 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. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS 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. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/vendor/stb/src/stb_truetype.c b/vendor/stb/src/stb_truetype.c
index e44c22c89..05c23f583 100644
--- a/vendor/stb/src/stb_truetype.c
+++ b/vendor/stb/src/stb_truetype.c
@@ -1,5 +1,2 @@
-#define STB_RECT_PACK_IMPLEMENTATION
-#include "stb_rect_pack.h"
-
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h" \ No newline at end of file
diff --git a/vendor/stb/src/stb_truetype_wasm.c b/vendor/stb/src/stb_truetype_wasm.c
deleted file mode 100644
index e0b1fdc77..000000000
--- a/vendor/stb/src/stb_truetype_wasm.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <stddef.h>
-
-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 e6defff5f..f1dcdf2a2 100644
--- a/vendor/stb/truetype/stb_truetype.odin
+++ b/vendor/stb/truetype/stb_truetype.odin
@@ -8,6 +8,7 @@ LIB :: (
"../lib/stb_truetype.lib" when ODIN_OS == .Windows
else "../lib/stb_truetype.a" when ODIN_OS == .Linux
else "../lib/darwin/stb_truetype.a" when ODIN_OS == .Darwin
+ else "../lib/stb_truetype_wasm.o" when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
else ""
)
@@ -15,10 +16,12 @@ when LIB != "" {
when !#exists(LIB) {
#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
}
+}
- foreign import stbtt { LIB }
-} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
foreign import stbtt "../lib/stb_truetype_wasm.o"
+} else when LIB != "" {
+ foreign import stbtt { LIB }
} 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
index 472419ccb..f36239086 100644
--- a/vendor/stb/truetype/stb_truetype_wasm.odin
+++ b/vendor/stb/truetype/stb_truetype_wasm.odin
@@ -1,82 +1,4 @@
-//+build wasm32, wasm64p32
+#+build wasm32, wasm64p32
package stb_truetype
-import "base:builtin"
-import "base:intrinsics"
-import "base:runtime"
-
-import "core:c"
-import "core:math"
-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 { return math.mod(x, y) }
-@(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);
+@(require) import _ "vendor:libc"
diff --git a/vendor/wasm/README.md b/vendor/wasm/README.md
index d0b0a2f6f..1aaeaa429 100644
--- a/vendor/wasm/README.md
+++ b/vendor/wasm/README.md
@@ -6,9 +6,9 @@ The `js_wasm32` target assumes that the WASM output will be ran within a web bro
## Example for `js_wasm32`
-```js
-<!-- Copy `vendor:wasm/js/runtime.js` into your web server -->
-<script type="text/javascript" src="runtime.js"></script>
+```html
+<!-- Copy `core:sys/wasm/js/odin.js` into your web server -->
+<script type="text/javascript" src="odin.js"></script>
<script type="text/javascript">
odin.runWasm(pathToWasm, consolePreElement);
</script>
diff --git a/vendor/wgpu/README.md b/vendor/wgpu/README.md
index 8b2c95b5e..1022e8541 100644
--- a/vendor/wgpu/README.md
+++ b/vendor/wgpu/README.md
@@ -11,8 +11,8 @@ 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.
+extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1),
+the bindings are for v22.1.0.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`),
diff --git a/vendor/wgpu/examples/glfw/main.odin b/vendor/wgpu/examples/glfw/main.odin
index bddd2c5f7..b57206371 100644
--- a/vendor/wgpu/examples/glfw/main.odin
+++ b/vendor/wgpu/examples/glfw/main.odin
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame,
loadOp = .Clear,
storeOp = .Store,
+ depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 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)
+ wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer)
diff --git a/vendor/wgpu/examples/glfw/os_glfw.odin b/vendor/wgpu/examples/glfw/os_glfw.odin
index 2b1817fa5..211b1ce97 100644
--- a/vendor/wgpu/examples/glfw/os_glfw.odin
+++ b/vendor/wgpu/examples/glfw/os_glfw.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package vendor_wgpu_example_triangle
import "core:time"
diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin
index fa0a84bd5..58e357f7a 100644
--- a/vendor/wgpu/examples/sdl2/main.odin
+++ b/vendor/wgpu/examples/sdl2/main.odin
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame,
loadOp = .Clear,
storeOp = .Store,
+ depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 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)
+ wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer)
diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin
index 0e6c5b57a..6ed70452f 100644
--- a/vendor/wgpu/examples/sdl2/os_sdl2.odin
+++ b/vendor/wgpu/examples/sdl2/os_sdl2.odin
@@ -1,4 +1,4 @@
-//+build !js
+#+build !js
package vendor_wgpu_example_triangle
import "core:c"
diff --git a/vendor/wgpu/glfwglue/glue.odin b/vendor/wgpu/glfwglue/glue.odin
index 83c497543..0da7d72b8 100644
--- a/vendor/wgpu/glfwglue/glue.odin
+++ b/vendor/wgpu/glfwglue/glue.odin
@@ -1,6 +1,6 @@
-//+build !linux
-//+build !windows
-//+build !darwin
+#+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/lib/wgpu-windows-x86_64-release/wgpu_native.dll b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll
index 650260bfc..b8f782a2f 100644
--- a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll
+++ b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.dll
Binary files 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
index b838c2695..864b7eb53 100644
--- 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
Binary files 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
index ea4044d81..7c9f95c33 100644
--- a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.lib
+++ b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.lib
Binary files 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
index b30090276..52865e174 100644
--- a/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdb
+++ b/vendor/wgpu/lib/wgpu-windows-x86_64-release/wgpu_native.pdb
Binary files differ
diff --git a/vendor/wgpu/sdl2glue/glue.odin b/vendor/wgpu/sdl2glue/glue.odin
index 9da9a0738..726569f4f 100644
--- a/vendor/wgpu/sdl2glue/glue.odin
+++ b/vendor/wgpu/sdl2glue/glue.odin
@@ -1,6 +1,6 @@
-//+build !linux
-//+build !windows
-//+build !darwin
+#+build !linux
+#+build !windows
+#+build !darwin
package wgpu_sdl2_glue
#panic("package wgpu/sdl2glue is not supported on the current target")
diff --git a/vendor/wgpu/sdl2glue/glue_linux.odin b/vendor/wgpu/sdl2glue/glue_linux.odin
index b01df251a..58ec90499 100644
--- a/vendor/wgpu/sdl2glue/glue_linux.odin
+++ b/vendor/wgpu/sdl2glue/glue_linux.odin
@@ -5,7 +5,9 @@ import "vendor:wgpu"
GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface {
window_info: sdl2.SysWMinfo
+ sdl2.VERSION(&window_info.version)
sdl2.GetWindowWMInfo(window, &window_info)
+
if window_info.subsystem == .WAYLAND {
display := window_info.info.wl.display
surface := window_info.info.wl.surface
diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js
index 4fe78c992..c100808e3 100644
--- a/vendor/wgpu/wgpu.js
+++ b/vendor/wgpu/wgpu.js
@@ -44,6 +44,7 @@ class WebGPUInterface {
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"],
+ DeviceLostReason: [undefined, "unknown", "destroyed"],
};
/** @type {WebGPUObjectManager<{}>} */
@@ -382,13 +383,19 @@ class WebGPUInterface {
*/
RenderPassColorAttachment(start) {
const viewIdx = this.mem.loadPtr(start + 4);
- const resolveTargetIdx = this.mem.loadPtr(start + 8);
+ const resolveTargetIdx = this.mem.loadPtr(start + 12);
+
+ let depthSlice = this.mem.loadU32(start + 8);
+ if (depthSlice == 0xFFFFFFFF) { // DEPTH_SLICE_UNDEFINED.
+ depthSlice = undefined;
+ }
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),
+ depthSlice: depthSlice,
+ loadOp: this.enumeration("LoadOp", start + 16),
+ storeOp: this.enumeration("StoreOp", start + 20),
clearValue: this.Color(start + 24),
};
}
@@ -950,14 +957,25 @@ class WebGPUInterface {
/**
* @param {number} adapterIdx
- * @param {number} propertiesPtr
+ * @param {number} infoPtr
*/
- wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => {
- this.assert(propertiesPtr != 0);
- // Unknown adapter.
- this.mem.storeI32(propertiesPtr + 28, 3);
+ wgpuAdapterGetInfo: (adapterIdx, infoPtr) => {
+ this.assert(infoPtr != 0);
+
// WebGPU backend.
- this.mem.storeI32(propertiesPtr + 32, 2);
+ this.mem.storeI32(infoPtr + 20, 2);
+ // Unknown adapter.
+ this.mem.storeI32(infoPtr + 24, 3);
+
+ // NOTE: I don't think getting the other fields in this struct is possible.
+ // `adapter.requestAdapterInfo` is deprecated.
+ },
+
+ /**
+ * @param {number} infoPtr
+ */
+ wgpuAdapterInfoFreeMembers: (infoPtr) => {
+ // NOTE: nothing to free.
},
/**
@@ -972,50 +990,6 @@ class WebGPUInterface {
/**
* @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
@@ -1040,14 +1014,69 @@ class WebGPUInterface {
};
}
+ let device;
let deviceIdx;
try {
- const device = await adapter.requestDevice(descriptor);
+ 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);
+ const messageLength = new TextEncoder().encode(e.message).length;
+ const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
+ this.mem.storeString(messageAddr, e.message);
+
+ callback(1, null, messageAddr, userdata);
+
+ this.mem.exports.wgpu_free(messageAddr);
+ }
+
+ let callbacksPtr = descriptorPtr + 24 + this.mem.intSize;
+
+ const deviceLostCallbackPtr = this.mem.loadPtr(callbacksPtr);
+ if (deviceLostCallbackPtr != 0) {
+ const deviceLostUserData = this.mem.loadPtr(callbacksPtr) + 4;
+ const deviceLostCallback = this.mem.exports.__indirect_function_table.get(deviceLostCallbackPtr);
+
+ device.lost.then((info) => {
+ const reason = this.enums.DeviceLostReason.indexOf(info.reason);
+
+ const messageLength = new TextEncoder().encode(info.message).length;
+ const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
+ this.mem.storeString(messageAddr, info.message);
+
+ deviceLostCallback(reason, messageAddr, deviceLostUserData);
+
+ this.mem.exports.wgpu_free(messageAddr);
+ });
+ }
+ callbacksPtr += 8;
+
+ // Skip over `nextInChain`.
+ callbacksPtr += 4;
+
+ const uncapturedErrorCallbackPtr = this.mem.loadPtr(callbacksPtr);
+ if (uncapturedErrorCallbackPtr != 0) {
+ const uncapturedErrorUserData = this.mem.loadPtr(callbacksPtr + 4);
+ const uncapturedErrorCallback = this.mem.exports.__indirect_function_table.get(uncapturedErrorCallbackPtr);
+
+ device.onuncapturederror = (ev) => {
+ let status = 4; // Unknown
+ if (ev.error instanceof GPUValidationError) {
+ status = 1; // Validation
+ } else if (ev.error instanceof GPUOutOfMemoryError) {
+ status = 2; // OutOfMemory
+ } else if (ev.error instanceof GPUInternalError) {
+ status = 3; // Internal
+ }
+
+ const messageLength = new TextEncoder().encode(ev.error.message).length;
+ const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
+ this.mem.storeString(messageAddr, ev.error.message);
+
+ uncapturedErrorCallback(status, messageAddr, uncapturedErrorUserData);
+
+ this.mem.exports.wgpu_free(messageAddr);
+ };
}
callback(0, deviceIdx, null, userdata);
@@ -1918,29 +1947,6 @@ class WebGPUInterface {
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 ---------------------- */
@@ -2646,23 +2652,23 @@ class WebGPUInterface {
const formatStr = navigator.gpu.getPreferredCanvasFormat();
const format = this.enums.TextureFormat.indexOf(formatStr);
- this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1);
+ this.mem.storeUint(capabilitiesPtr + 8, 1);
const formatAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(formatAddr, format);
- this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr);
+ this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize, 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);
+ this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*2, 1);
const presentModesAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(presentModesAddr, 0);
- this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr);
+ this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*3, presentModesAddr);
// Browser seems to support opaque (1) and premultiplied (2).
- this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2);
+ this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*4, 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);
+ this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*5, alphaModesAddr);
},
/**
@@ -2682,17 +2688,6 @@ class WebGPUInterface {
/**
* @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.
diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin
index af81dde56..ae4649aed 100644
--- a/vendor/wgpu/wgpu.odin
+++ b/vendor/wgpu/wgpu.odin
@@ -13,7 +13,7 @@ when ODIN_OS == .Windows {
@(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'")
+ #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/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -27,6 +27,8 @@ when ODIN_OS == .Windows {
"system:advapi32.lib",
"system:user32.lib",
"system:gdi32.lib",
+ "system:ole32.lib",
+ "system:oleaut32.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")
@@ -34,7 +36,7 @@ when ODIN_OS == .Windows {
@(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'")
+ #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/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -49,7 +51,7 @@ when ODIN_OS == .Windows {
@(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'")
+ #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/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -220,7 +222,8 @@ CullMode :: enum i32 {
DeviceLostReason :: enum i32 {
Undefined = 0x00000000,
- Destroyed = 0x00000001,
+ Unknown = 0x00000001,
+ Destroyed = 0x00000002,
}
ErrorFilter :: enum i32 {
@@ -264,6 +267,30 @@ FeatureName :: enum i32 {
PipelineStatisticsQuery,
StorageResourceBindingArray,
PartiallyBoundBindingArray,
+ TextureFormat16bitNorm,
+ TextureCompressionAstcHdr,
+ // TODO: requires wgpu.h api change
+ // TimestampQueryInsidePasses,
+ MappablePrimaryBuffers = 0x0003000E,
+ BufferBindingArray,
+ UniformBufferAndStorageTextureArrayNonUniformIndexing,
+ // TODO: requires wgpu.h api change
+ // AddressModeClampToZero,
+ // AddressModeClampToBorder,
+ // PolygonModeLine,
+ // PolygonModePoint,
+ // ConservativeRasterization,
+ // ClearTexture,
+ // SprivShaderPassThrough,
+ // MultiView,
+ VertexAttribute64bit = 0x00030019,
+ TextureFormatNv12,
+ RayTracingAccelarationStructure,
+ RayQuery,
+ ShaderF64,
+ ShaderI16,
+ ShaderPrimitiveIndex,
+ ShaderEarlyDepthTest,
}
FilterMode :: enum i32 {
@@ -520,6 +547,18 @@ TextureFormat :: enum i32 {
ASTC12x10UnormSrgb = 0x0000005D,
ASTC12x12Unorm = 0x0000005E,
ASTC12x12UnormSrgb = 0x0000005F,
+
+ // Native.
+
+ // From FeatureName.TextureFormat16bitNorm
+ R16Unorm = 0x00030001,
+ R16Snorm,
+ Rg16Unorm,
+ Rg16Snorm,
+ Rgba16Unorm,
+ Rgba16Snorm,
+ // From FeatureName.TextureFormatNv12
+ NV12,
}
TextureSampleType :: enum i32 {
@@ -581,13 +620,13 @@ VertexStepMode :: enum i32 {
VertexBufferNotUsed = 0x00000002,
}
-// WGSLFeatureName :: enum i32 {
-// Undefined = 0x00000000,
-// ReadonlyAndReadwriteStorageTextures = 0x00000001,
-// Packed4x8IntegerDotProduct = 0x00000002,
-// UnrestrictedPointerParameters = 0x00000003,
-// PointerCompositeAccess = 0x00000004,
-// }
+WGSLFeatureName :: enum i32 {
+ Undefined = 0x00000000,
+ ReadonlyAndReadwriteStorageTextures = 0x00000001,
+ Packed4x8IntegerDotProduct = 0x00000002,
+ UnrestrictedPointerParameters = 0x00000003,
+ PointerCompositeAccess = 0x00000004,
+}
BufferUsage :: enum i32 {
MapRead = 0x00000000,
@@ -634,22 +673,18 @@ TextureUsage :: enum i32 {
}
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)
+Proc :: distinct 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)
+BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* 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)
+InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
+QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
+ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
ChainedStruct :: struct {
next: ^ChainedStruct,
@@ -661,28 +696,23 @@ ChainedStructOut :: struct {
sType: SType,
}
-// AdapterInfo :: struct {
-// next: ^ChainedStructOut,
-// vendor: cstring,
-// architecture: cstring,
-// device: cstring,
-// description: cstring,
-// backendType: BackendType,
-// adapterType: AdapterType,
-// vendorID: u32,
-// deviceID: u32,
-// }
-
-AdapterProperties :: struct {
+AdapterInfo :: struct {
nextInChain: ^ChainedStructOut,
- vendorID: u32,
- vendorName: cstring,
+ vendor: cstring,
architecture: cstring,
- deviceID: u32,
- name: cstring,
- driverDescription: cstring,
- adapterType: AdapterType,
+ device: cstring,
+ description: cstring,
backendType: BackendType,
+ adapterType: AdapterType,
+ vendorID: u32,
+ deviceID: u32,
+}
+when ODIN_OS == .JS {
+ #assert(int(BackendType.WebGPU) == 2)
+ #assert(offset_of(AdapterInfo, backendType) == 20)
+
+ #assert(int(AdapterType.Unknown) == 3)
+ #assert(offset_of(AdapterInfo, adapterType) == 24)
}
BindGroupEntry :: struct {
@@ -943,6 +973,7 @@ StorageTextureBindingLayout :: struct {
SurfaceCapabilities :: struct {
nextInChain: ^ChainedStructOut,
+ usages: TextureUsageFlags,
formatCount: uint,
formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`,
presentModeCount: uint,
@@ -950,6 +981,16 @@ SurfaceCapabilities :: struct {
alphaModeCount: uint,
alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`,
}
+when ODIN_OS == .JS {
+ #assert(offset_of(SurfaceCapabilities, formatCount) == 8)
+ #assert(offset_of(SurfaceCapabilities, formats) == 8 + 1*size_of(int))
+
+ #assert(offset_of(SurfaceCapabilities, presentModeCount) == 8 + 2*size_of(int))
+ #assert(offset_of(SurfaceCapabilities, presentModes) == 8 + 3*size_of(int))
+
+ #assert(offset_of(SurfaceCapabilities, alphaModeCount) == 8 + 4*size_of(int))
+ #assert(offset_of(SurfaceCapabilities, alphaModes) == 8 + 5*size_of(int))
+}
SurfaceConfiguration :: struct {
nextInChain: ^ChainedStruct,
@@ -1040,6 +1081,12 @@ TextureViewDescriptor :: struct {
aspect: TextureAspect,
}
+UncapturedErrorCallbackInfo :: struct {
+ nextInChain: ^ChainedStruct,
+ callback: ErrorCallback,
+ userdata: rawptr,
+}
+
VertexAttribute :: struct {
format: VertexFormat,
offset: u64,
@@ -1120,12 +1167,21 @@ ProgrammableStageDescriptor :: struct {
RenderPassColorAttachment :: struct {
nextInChain: ^ChainedStruct,
/* NULLABLE */ view: TextureView,
- // depthSlice: u32,
+ depthSlice: u32,
/* NULLABLE */ resolveTarget: TextureView,
loadOp: LoadOp,
storeOp: StoreOp,
clearValue: Color,
}
+when ODIN_OS == .JS {
+ #assert(size_of(RenderPassColorAttachment) == 56)
+ #assert(offset_of(RenderPassColorAttachment, view) == 4)
+ #assert(offset_of(RenderPassColorAttachment, depthSlice) == 8)
+ #assert(offset_of(RenderPassColorAttachment, resolveTarget) == 12)
+ #assert(offset_of(RenderPassColorAttachment, loadOp) == 16)
+ #assert(offset_of(RenderPassColorAttachment, storeOp) == 20)
+ #assert(offset_of(RenderPassColorAttachment, clearValue) == 24)
+}
RequiredLimits :: struct {
nextInChain: ^ChainedStruct,
@@ -1194,6 +1250,10 @@ DeviceDescriptor :: struct {
defaultQueue: QueueDescriptor,
deviceLostCallback: DeviceLostCallback,
deviceLostUserdata: rawptr,
+ uncapturedErrorCallbackInfo: UncapturedErrorCallbackInfo,
+}
+when ODIN_OS == .JS {
+ #assert(offset_of(DeviceDescriptor, deviceLostCallback) == 24 + size_of(int))
}
RenderPassDescriptor :: struct {
@@ -1245,16 +1305,18 @@ foreign libwgpu {
// Methods of Adapter
@(link_name="wgpuAdapterEnumerateFeatures")
RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint ---
+ @(link_name="wgpuAdapterGetInfo")
+ RawAdapterGetInfo :: proc(adapter: Adapter, info: ^AdapterInfo) ---
@(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) ---
+ // Procs of AdapterInfo
+ AdapterInfoFreeMembers :: proc(adapterInfo: AdapterInfo) ---
+
// Methods of BindGroup
BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) ---
BindGroupReference :: proc(bindGroup: BindGroup) ---
@@ -1348,13 +1410,12 @@ foreign libwgpu {
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 ---
+ 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) ---
@@ -1455,9 +1516,8 @@ foreign libwgpu {
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) ---
+ SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
SurfaceUnconfigure :: proc(surface: Surface) ---
SurfaceReference :: proc(surface: Surface) ---
SurfaceRelease :: proc(surface: Surface) ---
@@ -1500,8 +1560,8 @@ AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool
return
}
-AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) {
- RawAdapterGetProperties(adapter, &properties)
+AdapterGetInfo :: proc(adapter: Adapter) -> (info: AdapterInfo) {
+ RawAdapterGetInfo(adapter, &info)
return
}
@@ -1634,8 +1694,8 @@ SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceT
// WGPU Native bindings
-BINDINGS_VERSION :: [4]u8{0, 19, 4, 1}
-BINDINGS_VERSION_STRING :: "0.19.4.1"
+BINDINGS_VERSION :: [4]u8{22, 1, 0, 1}
+BINDINGS_VERSION_STRING :: "22.1.0.1"
when ODIN_OS != .JS {
@(private="file", init)
diff --git a/vendor/x11/xlib/xlib_const.odin b/vendor/x11/xlib/xlib_const.odin
index 0466df76d..27af6a2d8 100644
--- a/vendor/x11/xlib/xlib_const.odin
+++ b/vendor/x11/xlib/xlib_const.odin
@@ -1,4 +1,4 @@
-//+build linux, freebsd, openbsd
+#+build linux, freebsd, openbsd
package xlib
/* ---- X11/extensions/XKB.h ---------------------------------------------------------*/
diff --git a/vendor/x11/xlib/xlib_keysym.odin b/vendor/x11/xlib/xlib_keysym.odin
index 594d966a4..61284c723 100644
--- a/vendor/x11/xlib/xlib_keysym.odin
+++ b/vendor/x11/xlib/xlib_keysym.odin
@@ -1,1681 +1,1681 @@
-//+build linux, freebsd, openbsd
+#+build linux, freebsd, openbsd
package xlib
KeySym :: enum u32 {
- XK_BackSpace = 0xff08, /* Back space, back char */
- XK_Tab = 0xff09,
- XK_Linefeed = 0xff0a, /* Linefeed, LF */
- XK_Clear = 0xff0b,
- XK_Return = 0xff0d, /* Return, enter */
- XK_Pause = 0xff13, /* Pause, hold */
- XK_Scroll_Lock = 0xff14,
- XK_Sys_Req = 0xff15,
- XK_Escape = 0xff1b,
- XK_Delete = 0xffff, /* Delete, rubout */
- XK_Multi_key = 0xff20, /* Multi-key character compose */
- XK_Codeinput = 0xff37,
- XK_SingleCandidate = 0xff3c,
- XK_MultipleCandidate = 0xff3d,
- XK_PreviousCandidate = 0xff3e,
- XK_Kanji = 0xff21, /* Kanji, Kanji convert */
- XK_Muhenkan = 0xff22, /* Cancel Conversion */
- XK_Henkan_Mode = 0xff23, /* Start/Stop Conversion */
- XK_Henkan = 0xff23, /* Alias for Henkan_Mode */
- XK_Romaji = 0xff24, /* to Romaji */
- XK_Hiragana = 0xff25, /* to Hiragana */
- XK_Katakana = 0xff26, /* to Katakana */
- XK_Hiragana_Katakana = 0xff27, /* Hiragana/Katakana toggle */
- XK_Zenkaku = 0xff28, /* to Zenkaku */
- XK_Hankaku = 0xff29, /* to Hankaku */
- XK_Zenkaku_Hankaku = 0xff2a, /* Zenkaku/Hankaku toggle */
- XK_Touroku = 0xff2b, /* Add to Dictionary */
- XK_Massyo = 0xff2c, /* Delete from Dictionary */
- XK_Kana_Lock = 0xff2d, /* Kana Lock */
- XK_Kana_Shift = 0xff2e, /* Kana Shift */
- XK_Eisu_Shift = 0xff2f, /* Alphanumeric Shift */
- XK_Eisu_toggle = 0xff30, /* Alphanumeric toggle */
- XK_Kanji_Bangou = 0xff37, /* Codeinput */
- XK_Zen_Koho = 0xff3d, /* Multiple/All Candidate(s) */
- XK_Mae_Koho = 0xff3e, /* Previous Candidate */
- XK_Home = 0xff50,
- XK_Left = 0xff51, /* Move left, left arrow */
- XK_Up = 0xff52, /* Move up, up arrow */
- XK_Right = 0xff53, /* Move right, right arrow */
- XK_Down = 0xff54, /* Move down, down arrow */
- XK_Prior = 0xff55, /* Prior, previous */
- XK_Page_Up = 0xff55,
- XK_Next = 0xff56, /* Next */
- XK_Page_Down = 0xff56,
- XK_End = 0xff57, /* EOL */
- XK_Begin = 0xff58, /* BOL */
- XK_Select = 0xff60, /* Select, mark */
- XK_Print = 0xff61,
- XK_Execute = 0xff62, /* Execute, run, do */
- XK_Insert = 0xff63, /* Insert, insert here */
- XK_Undo = 0xff65,
- XK_Redo = 0xff66, /* Redo, again */
- XK_Menu = 0xff67,
- XK_Find = 0xff68, /* Find, search */
- XK_Cancel = 0xff69, /* Cancel, stop, abort, exit */
- XK_Help = 0xff6a, /* Help */
- XK_Break = 0xff6b,
- XK_Mode_switch = 0xff7e, /* Character set switch */
- XK_script_switch = 0xff7e, /* Alias for mode_switch */
- XK_Num_Lock = 0xff7f,
- XK_KP_Space = 0xff80, /* Space */
- XK_KP_Tab = 0xff89,
- XK_KP_Enter = 0xff8d, /* Enter */
- XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */
- XK_KP_F2 = 0xff92,
- XK_KP_F3 = 0xff93,
- XK_KP_F4 = 0xff94,
- XK_KP_Home = 0xff95,
- XK_KP_Left = 0xff96,
- XK_KP_Up = 0xff97,
- XK_KP_Right = 0xff98,
- XK_KP_Down = 0xff99,
- XK_KP_Prior = 0xff9a,
- XK_KP_Page_Up = 0xff9a,
- XK_KP_Next = 0xff9b,
- XK_KP_Page_Down = 0xff9b,
- XK_KP_End = 0xff9c,
- XK_KP_Begin = 0xff9d,
- XK_KP_Insert = 0xff9e,
- XK_KP_Delete = 0xff9f,
- XK_KP_Equal = 0xffbd, /* Equals */
- XK_KP_Multiply = 0xffaa,
- XK_KP_Add = 0xffab,
- XK_KP_Separator = 0xffac, /* Separator, often comma */
- XK_KP_Subtract = 0xffad,
- XK_KP_Decimal = 0xffae,
- XK_KP_Divide = 0xffaf,
- XK_KP_0 = 0xffb0,
- XK_KP_1 = 0xffb1,
- XK_KP_2 = 0xffb2,
- XK_KP_3 = 0xffb3,
- XK_KP_4 = 0xffb4,
- XK_KP_5 = 0xffb5,
- XK_KP_6 = 0xffb6,
- XK_KP_7 = 0xffb7,
- XK_KP_8 = 0xffb8,
- XK_KP_9 = 0xffb9,
- XK_F1 = 0xffbe,
- XK_F2 = 0xffbf,
- XK_F3 = 0xffc0,
- XK_F4 = 0xffc1,
- XK_F5 = 0xffc2,
- XK_F6 = 0xffc3,
- XK_F7 = 0xffc4,
- XK_F8 = 0xffc5,
- XK_F9 = 0xffc6,
- XK_F10 = 0xffc7,
- XK_F11 = 0xffc8,
- XK_L1 = 0xffc8,
- XK_F12 = 0xffc9,
- XK_L2 = 0xffc9,
- XK_F13 = 0xffca,
- XK_L3 = 0xffca,
- XK_F14 = 0xffcb,
- XK_L4 = 0xffcb,
- XK_F15 = 0xffcc,
- XK_L5 = 0xffcc,
- XK_F16 = 0xffcd,
- XK_L6 = 0xffcd,
- XK_F17 = 0xffce,
- XK_L7 = 0xffce,
- XK_F18 = 0xffcf,
- XK_L8 = 0xffcf,
- XK_F19 = 0xffd0,
- XK_L9 = 0xffd0,
- XK_F20 = 0xffd1,
- XK_L10 = 0xffd1,
- XK_F21 = 0xffd2,
- XK_R1 = 0xffd2,
- XK_F22 = 0xffd3,
- XK_R2 = 0xffd3,
- XK_F23 = 0xffd4,
- XK_R3 = 0xffd4,
- XK_F24 = 0xffd5,
- XK_R4 = 0xffd5,
- XK_F25 = 0xffd6,
- XK_R5 = 0xffd6,
- XK_F26 = 0xffd7,
- XK_R6 = 0xffd7,
- XK_F27 = 0xffd8,
- XK_R7 = 0xffd8,
- XK_F28 = 0xffd9,
- XK_R8 = 0xffd9,
- XK_F29 = 0xffda,
- XK_R9 = 0xffda,
- XK_F30 = 0xffdb,
- XK_R10 = 0xffdb,
- XK_F31 = 0xffdc,
- XK_R11 = 0xffdc,
- XK_F32 = 0xffdd,
- XK_R12 = 0xffdd,
- XK_F33 = 0xffde,
- XK_R13 = 0xffde,
- XK_F34 = 0xffdf,
- XK_R14 = 0xffdf,
- XK_F35 = 0xffe0,
- XK_R15 = 0xffe0,
- XK_Shift_L = 0xffe1, /* Left shift */
- XK_Shift_R = 0xffe2, /* Right shift */
- XK_Control_L = 0xffe3, /* Left control */
- XK_Control_R = 0xffe4, /* Right control */
- XK_Caps_Lock = 0xffe5, /* Caps lock */
- XK_Shift_Lock = 0xffe6, /* Shift lock */
- XK_Meta_L = 0xffe7, /* Left meta */
- XK_Meta_R = 0xffe8, /* Right meta */
- XK_Alt_L = 0xffe9, /* Left alt */
- XK_Alt_R = 0xffea, /* Right alt */
- XK_Super_L = 0xffeb, /* Left super */
- XK_Super_R = 0xffec, /* Right super */
- XK_Hyper_L = 0xffed, /* Left hyper */
- XK_Hyper_R = 0xffee, /* Right hyper */
- XK_ISO_Lock = 0xfe01,
- XK_ISO_Level2_Latch = 0xfe02,
- XK_ISO_Level3_Shift = 0xfe03,
- XK_ISO_Level3_Latch = 0xfe04,
- XK_ISO_Level3_Lock = 0xfe05,
- XK_ISO_Group_Shift = 0xff7e, /* Alias for mode_switch */
- XK_ISO_Group_Latch = 0xfe06,
- XK_ISO_Group_Lock = 0xfe07,
- XK_ISO_Next_Group = 0xfe08,
- XK_ISO_Next_Group_Lock = 0xfe09,
- XK_ISO_Prev_Group = 0xfe0a,
- XK_ISO_Prev_Group_Lock = 0xfe0b,
- XK_ISO_First_Group = 0xfe0c,
- XK_ISO_First_Group_Lock = 0xfe0d,
- XK_ISO_Last_Group = 0xfe0e,
- XK_ISO_Last_Group_Lock = 0xfe0f,
- XK_ISO_Left_Tab = 0xfe20,
- XK_ISO_Move_Line_Up = 0xfe21,
- XK_ISO_Move_Line_Down = 0xfe22,
- XK_ISO_Partial_Line_Up = 0xfe23,
- XK_ISO_Partial_Line_Down = 0xfe24,
- XK_ISO_Partial_Space_Left = 0xfe25,
- XK_ISO_Partial_Space_Right = 0xfe26,
- XK_ISO_Set_Margin_Left = 0xfe27,
- XK_ISO_Set_Margin_Right = 0xfe28,
- XK_ISO_Release_Margin_Left = 0xfe29,
- XK_ISO_Release_Margin_Right = 0xfe2a,
- XK_ISO_Release_Both_Margins = 0xfe2b,
- XK_ISO_Fast_Cursor_Left = 0xfe2c,
- XK_ISO_Fast_Cursor_Right = 0xfe2d,
- XK_ISO_Fast_Cursor_Up = 0xfe2e,
- XK_ISO_Fast_Cursor_Down = 0xfe2f,
- XK_ISO_Continuous_Underline = 0xfe30,
- XK_ISO_Discontinuous_Underline = 0xfe31,
- XK_ISO_Emphasize = 0xfe32,
- XK_ISO_Center_Object = 0xfe33,
- XK_ISO_Enter = 0xfe34,
- XK_dead_grave = 0xfe50,
- XK_dead_acute = 0xfe51,
- XK_dead_circumflex = 0xfe52,
- XK_dead_tilde = 0xfe53,
- XK_dead_macron = 0xfe54,
- XK_dead_breve = 0xfe55,
- XK_dead_abovedot = 0xfe56,
- XK_dead_diaeresis = 0xfe57,
- XK_dead_abovering = 0xfe58,
- XK_dead_doubleacute = 0xfe59,
- XK_dead_caron = 0xfe5a,
- XK_dead_cedilla = 0xfe5b,
- XK_dead_ogonek = 0xfe5c,
- XK_dead_iota = 0xfe5d,
- XK_dead_voiced_sound = 0xfe5e,
- XK_dead_semivoiced_sound = 0xfe5f,
- XK_dead_belowdot = 0xfe60,
- XK_dead_hook = 0xfe61,
- XK_dead_horn = 0xfe62,
- XK_First_Virtual_Screen = 0xfed0,
- XK_Prev_Virtual_Screen = 0xfed1,
- XK_Next_Virtual_Screen = 0xfed2,
- XK_Last_Virtual_Screen = 0xfed4,
- XK_Terminate_Server = 0xfed5,
- XK_AccessX_Enable = 0xfe70,
- XK_AccessX_Feedback_Enable = 0xfe71,
- XK_RepeatKeys_Enable = 0xfe72,
- XK_SlowKeys_Enable = 0xfe73,
- XK_BounceKeys_Enable = 0xfe74,
- XK_StickyKeys_Enable = 0xfe75,
- XK_MouseKeys_Enable = 0xfe76,
- XK_MouseKeys_Accel_Enable = 0xfe77,
- XK_Overlay1_Enable = 0xfe78,
- XK_Overlay2_Enable = 0xfe79,
- XK_AudibleBell_Enable = 0xfe7a,
- XK_Pointer_Left = 0xfee0,
- XK_Pointer_Right = 0xfee1,
- XK_Pointer_Up = 0xfee2,
- XK_Pointer_Down = 0xfee3,
- XK_Pointer_UpLeft = 0xfee4,
- XK_Pointer_UpRight = 0xfee5,
- XK_Pointer_DownLeft = 0xfee6,
- XK_Pointer_DownRight = 0xfee7,
- XK_Pointer_Button_Dflt = 0xfee8,
- XK_Pointer_Button1 = 0xfee9,
- XK_Pointer_Button2 = 0xfeea,
- XK_Pointer_Button3 = 0xfeeb,
- XK_Pointer_Button4 = 0xfeec,
- XK_Pointer_Button5 = 0xfeed,
- XK_Pointer_DblClick_Dflt = 0xfeee,
- XK_Pointer_DblClick1 = 0xfeef,
- XK_Pointer_DblClick2 = 0xfef0,
- XK_Pointer_DblClick3 = 0xfef1,
- XK_Pointer_DblClick4 = 0xfef2,
- XK_Pointer_DblClick5 = 0xfef3,
- XK_Pointer_Drag_Dflt = 0xfef4,
- XK_Pointer_Drag1 = 0xfef5,
- XK_Pointer_Drag2 = 0xfef6,
- XK_Pointer_Drag3 = 0xfef7,
- XK_Pointer_Drag4 = 0xfef8,
- XK_Pointer_Drag5 = 0xfefd,
- XK_Pointer_EnableKeys = 0xfef9,
- XK_Pointer_Accelerate = 0xfefa,
- XK_Pointer_DfltBtnNext = 0xfefb,
- XK_Pointer_DfltBtnPrev = 0xfefc,
- XK_3270_Duplicate = 0xfd01,
- XK_3270_FieldMark = 0xfd02,
- XK_3270_Right2 = 0xfd03,
- XK_3270_Left2 = 0xfd04,
- XK_3270_BackTab = 0xfd05,
- XK_3270_EraseEOF = 0xfd06,
- XK_3270_EraseInput = 0xfd07,
- XK_3270_Reset = 0xfd08,
- XK_3270_Quit = 0xfd09,
- XK_3270_PA1 = 0xfd0a,
- XK_3270_PA2 = 0xfd0b,
- XK_3270_PA3 = 0xfd0c,
- XK_3270_Test = 0xfd0d,
- XK_3270_Attn = 0xfd0e,
- XK_3270_CursorBlink = 0xfd0f,
- XK_3270_AltCursor = 0xfd10,
- XK_3270_KeyClick = 0xfd11,
- XK_3270_Jump = 0xfd12,
- XK_3270_Ident = 0xfd13,
- XK_3270_Rule = 0xfd14,
- XK_3270_Copy = 0xfd15,
- XK_3270_Play = 0xfd16,
- XK_3270_Setup = 0xfd17,
- XK_3270_Record = 0xfd18,
- XK_3270_ChangeScreen = 0xfd19,
- XK_3270_DeleteWord = 0xfd1a,
- XK_3270_ExSelect = 0xfd1b,
- XK_3270_CursorSelect = 0xfd1c,
- XK_3270_PrintScreen = 0xfd1d,
- XK_3270_Enter = 0xfd1e,
- XK_space = 0x0020, /* U+0020 SPACE */
- XK_exclam = 0x0021, /* U+0021 EXCLAMATION MARK */
- XK_quotedbl = 0x0022, /* U+0022 QUOTATION MARK */
- XK_numbersign = 0x0023, /* U+0023 NUMBER SIGN */
- XK_dollar = 0x0024, /* U+0024 DOLLAR SIGN */
- XK_percent = 0x0025, /* U+0025 PERCENT SIGN */
- XK_ampersand = 0x0026, /* U+0026 AMPERSAND */
- XK_apostrophe = 0x0027, /* U+0027 APOSTROPHE */
- XK_quoteright = 0x0027, /* deprecated */
- XK_parenleft = 0x0028, /* U+0028 LEFT PARENTHESIS */
- XK_parenright = 0x0029, /* U+0029 RIGHT PARENTHESIS */
- XK_asterisk = 0x002a, /* U+002A ASTERISK */
- XK_plus = 0x002b, /* U+002B PLUS SIGN */
- XK_comma = 0x002c, /* U+002C COMMA */
- XK_minus = 0x002d, /* U+002D HYPHEN-MINUS */
- XK_period = 0x002e, /* U+002E FULL STOP */
- XK_slash = 0x002f, /* U+002F SOLIDUS */
- XK_0 = 0x0030, /* U+0030 DIGIT ZERO */
- XK_1 = 0x0031, /* U+0031 DIGIT ONE */
- XK_2 = 0x0032, /* U+0032 DIGIT TWO */
- XK_3 = 0x0033, /* U+0033 DIGIT THREE */
- XK_4 = 0x0034, /* U+0034 DIGIT FOUR */
- XK_5 = 0x0035, /* U+0035 DIGIT FIVE */
- XK_6 = 0x0036, /* U+0036 DIGIT SIX */
- XK_7 = 0x0037, /* U+0037 DIGIT SEVEN */
- XK_8 = 0x0038, /* U+0038 DIGIT EIGHT */
- XK_9 = 0x0039, /* U+0039 DIGIT NINE */
- XK_colon = 0x003a, /* U+003A COLON */
- XK_semicolon = 0x003b, /* U+003B SEMICOLON */
- XK_less = 0x003c, /* U+003C LESS-THAN SIGN */
- XK_equal = 0x003d, /* U+003D EQUALS SIGN */
- XK_greater = 0x003e, /* U+003E GREATER-THAN SIGN */
- XK_question = 0x003f, /* U+003F QUESTION MARK */
- XK_at = 0x0040, /* U+0040 COMMERCIAL AT */
- XK_A = 0x0041, /* U+0041 LATIN CAPITAL LETTER A */
- XK_B = 0x0042, /* U+0042 LATIN CAPITAL LETTER B */
- XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */
- XK_D = 0x0044, /* U+0044 LATIN CAPITAL LETTER D */
- XK_E = 0x0045, /* U+0045 LATIN CAPITAL LETTER E */
- XK_F = 0x0046, /* U+0046 LATIN CAPITAL LETTER F */
- XK_G = 0x0047, /* U+0047 LATIN CAPITAL LETTER G */
- XK_H = 0x0048, /* U+0048 LATIN CAPITAL LETTER H */
- XK_I = 0x0049, /* U+0049 LATIN CAPITAL LETTER I */
- XK_J = 0x004a, /* U+004A LATIN CAPITAL LETTER J */
- XK_K = 0x004b, /* U+004B LATIN CAPITAL LETTER K */
- XK_L = 0x004c, /* U+004C LATIN CAPITAL LETTER L */
- XK_M = 0x004d, /* U+004D LATIN CAPITAL LETTER M */
- XK_N = 0x004e, /* U+004E LATIN CAPITAL LETTER N */
- XK_O = 0x004f, /* U+004F LATIN CAPITAL LETTER O */
- XK_P = 0x0050, /* U+0050 LATIN CAPITAL LETTER P */
- XK_Q = 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */
- XK_R = 0x0052, /* U+0052 LATIN CAPITAL LETTER R */
- XK_S = 0x0053, /* U+0053 LATIN CAPITAL LETTER S */
- XK_T = 0x0054, /* U+0054 LATIN CAPITAL LETTER T */
- XK_U = 0x0055, /* U+0055 LATIN CAPITAL LETTER U */
- XK_V = 0x0056, /* U+0056 LATIN CAPITAL LETTER V */
- XK_W = 0x0057, /* U+0057 LATIN CAPITAL LETTER W */
- XK_X = 0x0058, /* U+0058 LATIN CAPITAL LETTER X */
- XK_Y = 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */
- XK_Z = 0x005a, /* U+005A LATIN CAPITAL LETTER Z */
- XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */
- XK_backslash = 0x005c, /* U+005C REVERSE SOLIDUS */
- XK_bracketright = 0x005d, /* U+005D RIGHT SQUARE BRACKET */
- XK_asciicircum = 0x005e, /* U+005E CIRCUMFLEX ACCENT */
- XK_underscore = 0x005f, /* U+005F LOW LINE */
- XK_grave = 0x0060, /* U+0060 GRAVE ACCENT */
- XK_quoteleft = 0x0060, /* deprecated */
- XK_a = 0x0061, /* U+0061 LATIN SMALL LETTER A */
- XK_b = 0x0062, /* U+0062 LATIN SMALL LETTER B */
- XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */
- XK_d = 0x0064, /* U+0064 LATIN SMALL LETTER D */
- XK_e = 0x0065, /* U+0065 LATIN SMALL LETTER E */
- XK_f = 0x0066, /* U+0066 LATIN SMALL LETTER F */
- XK_g = 0x0067, /* U+0067 LATIN SMALL LETTER G */
- XK_h = 0x0068, /* U+0068 LATIN SMALL LETTER H */
- XK_i = 0x0069, /* U+0069 LATIN SMALL LETTER I */
- XK_j = 0x006a, /* U+006A LATIN SMALL LETTER J */
- XK_k = 0x006b, /* U+006B LATIN SMALL LETTER K */
- XK_l = 0x006c, /* U+006C LATIN SMALL LETTER L */
- XK_m = 0x006d, /* U+006D LATIN SMALL LETTER M */
- XK_n = 0x006e, /* U+006E LATIN SMALL LETTER N */
- XK_o = 0x006f, /* U+006F LATIN SMALL LETTER O */
- XK_p = 0x0070, /* U+0070 LATIN SMALL LETTER P */
- XK_q = 0x0071, /* U+0071 LATIN SMALL LETTER Q */
- XK_r = 0x0072, /* U+0072 LATIN SMALL LETTER R */
- XK_s = 0x0073, /* U+0073 LATIN SMALL LETTER S */
- XK_t = 0x0074, /* U+0074 LATIN SMALL LETTER T */
- XK_u = 0x0075, /* U+0075 LATIN SMALL LETTER U */
- XK_v = 0x0076, /* U+0076 LATIN SMALL LETTER V */
- XK_w = 0x0077, /* U+0077 LATIN SMALL LETTER W */
- XK_x = 0x0078, /* U+0078 LATIN SMALL LETTER X */
- XK_y = 0x0079, /* U+0079 LATIN SMALL LETTER Y */
- XK_z = 0x007a, /* U+007A LATIN SMALL LETTER Z */
- XK_braceleft = 0x007b, /* U+007B LEFT CURLY BRACKET */
- XK_bar = 0x007c, /* U+007C VERTICAL LINE */
- XK_braceright = 0x007d, /* U+007D RIGHT CURLY BRACKET */
- XK_asciitilde = 0x007e, /* U+007E TILDE */
- XK_nobreakspace = 0x00a0, /* U+00A0 NO-BREAK SPACE */
- XK_exclamdown = 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */
- XK_cent = 0x00a2, /* U+00A2 CENT SIGN */
- XK_sterling = 0x00a3, /* U+00A3 POUND SIGN */
- XK_currency = 0x00a4, /* U+00A4 CURRENCY SIGN */
- XK_yen = 0x00a5, /* U+00A5 YEN SIGN */
- XK_brokenbar = 0x00a6, /* U+00A6 BROKEN BAR */
- XK_section = 0x00a7, /* U+00A7 SECTION SIGN */
- XK_diaeresis = 0x00a8, /* U+00A8 DIAERESIS */
- XK_copyright = 0x00a9, /* U+00A9 COPYRIGHT SIGN */
- XK_ordfeminine = 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */
- XK_guillemotleft = 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
- XK_notsign = 0x00ac, /* U+00AC NOT SIGN */
- XK_hyphen = 0x00ad, /* U+00AD SOFT HYPHEN */
- XK_registered = 0x00ae, /* U+00AE REGISTERED SIGN */
- XK_macron = 0x00af, /* U+00AF MACRON */
- XK_degree = 0x00b0, /* U+00B0 DEGREE SIGN */
- XK_plusminus = 0x00b1, /* U+00B1 PLUS-MINUS SIGN */
- XK_twosuperior = 0x00b2, /* U+00B2 SUPERSCRIPT TWO */
- XK_threesuperior = 0x00b3, /* U+00B3 SUPERSCRIPT THREE */
- XK_acute = 0x00b4, /* U+00B4 ACUTE ACCENT */
- XK_mu = 0x00b5, /* U+00B5 MICRO SIGN */
- XK_paragraph = 0x00b6, /* U+00B6 PILCROW SIGN */
- XK_periodcentered = 0x00b7, /* U+00B7 MIDDLE DOT */
- XK_cedilla = 0x00b8, /* U+00B8 CEDILLA */
- XK_onesuperior = 0x00b9, /* U+00B9 SUPERSCRIPT ONE */
- XK_masculine = 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */
- XK_guillemotright = 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
- XK_onequarter = 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */
- XK_onehalf = 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */
- XK_threequarters = 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */
- XK_questiondown = 0x00bf, /* U+00BF INVERTED QUESTION MARK */
- XK_Agrave = 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */
- XK_Aacute = 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */
- XK_Acircumflex = 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
- XK_Atilde = 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */
- XK_Adiaeresis = 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */
- XK_Aring = 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */
- XK_AE = 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */
- XK_Ccedilla = 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */
- XK_Egrave = 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */
- XK_Eacute = 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */
- XK_Ecircumflex = 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
- XK_Ediaeresis = 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */
- XK_Igrave = 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */
- XK_Iacute = 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */
- XK_Icircumflex = 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
- XK_Idiaeresis = 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */
- XK_ETH = 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */
- XK_Eth = 0x00d0, /* deprecated */
- XK_Ntilde = 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */
- XK_Ograve = 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */
- XK_Oacute = 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */
- XK_Ocircumflex = 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
- XK_Otilde = 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */
- XK_Odiaeresis = 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */
- XK_multiply = 0x00d7, /* U+00D7 MULTIPLICATION SIGN */
- XK_Oslash = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
- XK_Ooblique = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
- XK_Ugrave = 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */
- XK_Uacute = 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */
- XK_Ucircumflex = 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
- XK_Udiaeresis = 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */
- XK_Yacute = 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */
- XK_THORN = 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */
- XK_Thorn = 0x00de, /* deprecated */
- XK_ssharp = 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */
- XK_agrave = 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */
- XK_aacute = 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */
- XK_acircumflex = 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */
- XK_atilde = 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */
- XK_adiaeresis = 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */
- XK_aring = 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */
- XK_ae = 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */
- XK_ccedilla = 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */
- XK_egrave = 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */
- XK_eacute = 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */
- XK_ecircumflex = 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */
- XK_ediaeresis = 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */
- XK_igrave = 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */
- XK_iacute = 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */
- XK_icircumflex = 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */
- XK_idiaeresis = 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */
- XK_eth = 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */
- XK_ntilde = 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */
- XK_ograve = 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */
- XK_oacute = 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */
- XK_ocircumflex = 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */
- XK_otilde = 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */
- XK_odiaeresis = 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */
- XK_division = 0x00f7, /* U+00F7 DIVISION SIGN */
- XK_oslash = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
- XK_ooblique = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
- XK_ugrave = 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */
- XK_uacute = 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */
- XK_ucircumflex = 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */
- XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */
- XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
- XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */
- XK_ydiaeresis = 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
- XK_Aogonek = 0x01a1, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK */
- XK_breve = 0x01a2, /* U+02D8 BREVE */
- XK_Lstroke = 0x01a3, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */
- XK_Lcaron = 0x01a5, /* U+013D LATIN CAPITAL LETTER L WITH CARON */
- XK_Sacute = 0x01a6, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE */
- XK_Scaron = 0x01a9, /* U+0160 LATIN CAPITAL LETTER S WITH CARON */
- XK_Scedilla = 0x01aa, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */
- XK_Tcaron = 0x01ab, /* U+0164 LATIN CAPITAL LETTER T WITH CARON */
- XK_Zacute = 0x01ac, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE */
- XK_Zcaron = 0x01ae, /* U+017D LATIN CAPITAL LETTER Z WITH CARON */
- XK_Zabovedot = 0x01af, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE */
- XK_aogonek = 0x01b1, /* U+0105 LATIN SMALL LETTER A WITH OGONEK */
- XK_ogonek = 0x01b2, /* U+02DB OGONEK */
- XK_lstroke = 0x01b3, /* U+0142 LATIN SMALL LETTER L WITH STROKE */
- XK_lcaron = 0x01b5, /* U+013E LATIN SMALL LETTER L WITH CARON */
- XK_sacute = 0x01b6, /* U+015B LATIN SMALL LETTER S WITH ACUTE */
- XK_caron = 0x01b7, /* U+02C7 CARON */
- XK_scaron = 0x01b9, /* U+0161 LATIN SMALL LETTER S WITH CARON */
- XK_scedilla = 0x01ba, /* U+015F LATIN SMALL LETTER S WITH CEDILLA */
- XK_tcaron = 0x01bb, /* U+0165 LATIN SMALL LETTER T WITH CARON */
- XK_zacute = 0x01bc, /* U+017A LATIN SMALL LETTER Z WITH ACUTE */
- XK_doubleacute = 0x01bd, /* U+02DD DOUBLE ACUTE ACCENT */
- XK_zcaron = 0x01be, /* U+017E LATIN SMALL LETTER Z WITH CARON */
- XK_zabovedot = 0x01bf, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE */
- XK_Racute = 0x01c0, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE */
- XK_Abreve = 0x01c3, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE */
- XK_Lacute = 0x01c5, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE */
- XK_Cacute = 0x01c6, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE */
- XK_Ccaron = 0x01c8, /* U+010C LATIN CAPITAL LETTER C WITH CARON */
- XK_Eogonek = 0x01ca, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK */
- XK_Ecaron = 0x01cc, /* U+011A LATIN CAPITAL LETTER E WITH CARON */
- XK_Dcaron = 0x01cf, /* U+010E LATIN CAPITAL LETTER D WITH CARON */
- XK_Dstroke = 0x01d0, /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */
- XK_Nacute = 0x01d1, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE */
- XK_Ncaron = 0x01d2, /* U+0147 LATIN CAPITAL LETTER N WITH CARON */
- XK_Odoubleacute = 0x01d5, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
- XK_Rcaron = 0x01d8, /* U+0158 LATIN CAPITAL LETTER R WITH CARON */
- XK_Uring = 0x01d9, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE */
- XK_Udoubleacute = 0x01db, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
- XK_Tcedilla = 0x01de, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA */
- XK_racute = 0x01e0, /* U+0155 LATIN SMALL LETTER R WITH ACUTE */
- XK_abreve = 0x01e3, /* U+0103 LATIN SMALL LETTER A WITH BREVE */
- XK_lacute = 0x01e5, /* U+013A LATIN SMALL LETTER L WITH ACUTE */
- XK_cacute = 0x01e6, /* U+0107 LATIN SMALL LETTER C WITH ACUTE */
- XK_ccaron = 0x01e8, /* U+010D LATIN SMALL LETTER C WITH CARON */
- XK_eogonek = 0x01ea, /* U+0119 LATIN SMALL LETTER E WITH OGONEK */
- XK_ecaron = 0x01ec, /* U+011B LATIN SMALL LETTER E WITH CARON */
- XK_dcaron = 0x01ef, /* U+010F LATIN SMALL LETTER D WITH CARON */
- XK_dstroke = 0x01f0, /* U+0111 LATIN SMALL LETTER D WITH STROKE */
- XK_nacute = 0x01f1, /* U+0144 LATIN SMALL LETTER N WITH ACUTE */
- XK_ncaron = 0x01f2, /* U+0148 LATIN SMALL LETTER N WITH CARON */
- XK_odoubleacute = 0x01f5, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE */
- XK_udoubleacute = 0x01fb, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE */
- XK_rcaron = 0x01f8, /* U+0159 LATIN SMALL LETTER R WITH CARON */
- XK_uring = 0x01f9, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE */
- XK_tcedilla = 0x01fe, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA */
- XK_abovedot = 0x01ff, /* U+02D9 DOT ABOVE */
- XK_Hstroke = 0x02a1, /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */
- XK_Hcircumflex = 0x02a6, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
- XK_Iabovedot = 0x02a9, /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */
- XK_Gbreve = 0x02ab, /* U+011E LATIN CAPITAL LETTER G WITH BREVE */
- XK_Jcircumflex = 0x02ac, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
- XK_hstroke = 0x02b1, /* U+0127 LATIN SMALL LETTER H WITH STROKE */
- XK_hcircumflex = 0x02b6, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX */
- XK_idotless = 0x02b9, /* U+0131 LATIN SMALL LETTER DOTLESS I */
- XK_gbreve = 0x02bb, /* U+011F LATIN SMALL LETTER G WITH BREVE */
- XK_jcircumflex = 0x02bc, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX */
- XK_Cabovedot = 0x02c5, /* U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE */
- XK_Ccircumflex = 0x02c6, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
- XK_Gabovedot = 0x02d5, /* U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE */
- XK_Gcircumflex = 0x02d8, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
- XK_Ubreve = 0x02dd, /* U+016C LATIN CAPITAL LETTER U WITH BREVE */
- XK_Scircumflex = 0x02de, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
- XK_cabovedot = 0x02e5, /* U+010B LATIN SMALL LETTER C WITH DOT ABOVE */
- XK_ccircumflex = 0x02e6, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX */
- XK_gabovedot = 0x02f5, /* U+0121 LATIN SMALL LETTER G WITH DOT ABOVE */
- XK_gcircumflex = 0x02f8, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX */
- XK_ubreve = 0x02fd, /* U+016D LATIN SMALL LETTER U WITH BREVE */
- XK_scircumflex = 0x02fe, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX */
- XK_kra = 0x03a2, /* U+0138 LATIN SMALL LETTER KRA */
- XK_kappa = 0x03a2, /* deprecated */
- XK_Rcedilla = 0x03a3, /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */
- XK_Itilde = 0x03a5, /* U+0128 LATIN CAPITAL LETTER I WITH TILDE */
- XK_Lcedilla = 0x03a6, /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */
- XK_Emacron = 0x03aa, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */
- XK_Gcedilla = 0x03ab, /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */
- XK_Tslash = 0x03ac, /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */
- XK_rcedilla = 0x03b3, /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */
- XK_itilde = 0x03b5, /* U+0129 LATIN SMALL LETTER I WITH TILDE */
- XK_lcedilla = 0x03b6, /* U+013C LATIN SMALL LETTER L WITH CEDILLA */
- XK_emacron = 0x03ba, /* U+0113 LATIN SMALL LETTER E WITH MACRON */
- XK_gcedilla = 0x03bb, /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */
- XK_tslash = 0x03bc, /* U+0167 LATIN SMALL LETTER T WITH STROKE */
- XK_ENG = 0x03bd, /* U+014A LATIN CAPITAL LETTER ENG */
- XK_eng = 0x03bf, /* U+014B LATIN SMALL LETTER ENG */
- XK_Amacron = 0x03c0, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */
- XK_Iogonek = 0x03c7, /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */
- XK_Eabovedot = 0x03cc, /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */
- XK_Imacron = 0x03cf, /* U+012A LATIN CAPITAL LETTER I WITH MACRON */
- XK_Ncedilla = 0x03d1, /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */
- XK_Omacron = 0x03d2, /* U+014C LATIN CAPITAL LETTER O WITH MACRON */
- XK_Kcedilla = 0x03d3, /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */
- XK_Uogonek = 0x03d9, /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */
- XK_Utilde = 0x03dd, /* U+0168 LATIN CAPITAL LETTER U WITH TILDE */
- XK_Umacron = 0x03de, /* U+016A LATIN CAPITAL LETTER U WITH MACRON */
- XK_amacron = 0x03e0, /* U+0101 LATIN SMALL LETTER A WITH MACRON */
- XK_iogonek = 0x03e7, /* U+012F LATIN SMALL LETTER I WITH OGONEK */
- XK_eabovedot = 0x03ec, /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */
- XK_imacron = 0x03ef, /* U+012B LATIN SMALL LETTER I WITH MACRON */
- XK_ncedilla = 0x03f1, /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */
- XK_omacron = 0x03f2, /* U+014D LATIN SMALL LETTER O WITH MACRON */
- XK_kcedilla = 0x03f3, /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */
- XK_uogonek = 0x03f9, /* U+0173 LATIN SMALL LETTER U WITH OGONEK */
- XK_utilde = 0x03fd, /* U+0169 LATIN SMALL LETTER U WITH TILDE */
- XK_umacron = 0x03fe, /* U+016B LATIN SMALL LETTER U WITH MACRON */
- XK_Babovedot = 0x1001e02, /* U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE */
- XK_babovedot = 0x1001e03, /* U+1E03 LATIN SMALL LETTER B WITH DOT ABOVE */
- XK_Dabovedot = 0x1001e0a, /* U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE */
- XK_Wgrave = 0x1001e80, /* U+1E80 LATIN CAPITAL LETTER W WITH GRAVE */
- XK_Wacute = 0x1001e82, /* U+1E82 LATIN CAPITAL LETTER W WITH ACUTE */
- XK_dabovedot = 0x1001e0b, /* U+1E0B LATIN SMALL LETTER D WITH DOT ABOVE */
- XK_Ygrave = 0x1001ef2, /* U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE */
- XK_Fabovedot = 0x1001e1e, /* U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE */
- XK_fabovedot = 0x1001e1f, /* U+1E1F LATIN SMALL LETTER F WITH DOT ABOVE */
- XK_Mabovedot = 0x1001e40, /* U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE */
- XK_mabovedot = 0x1001e41, /* U+1E41 LATIN SMALL LETTER M WITH DOT ABOVE */
- XK_Pabovedot = 0x1001e56, /* U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE */
- XK_wgrave = 0x1001e81, /* U+1E81 LATIN SMALL LETTER W WITH GRAVE */
- XK_pabovedot = 0x1001e57, /* U+1E57 LATIN SMALL LETTER P WITH DOT ABOVE */
- XK_wacute = 0x1001e83, /* U+1E83 LATIN SMALL LETTER W WITH ACUTE */
- XK_Sabovedot = 0x1001e60, /* U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE */
- XK_ygrave = 0x1001ef3, /* U+1EF3 LATIN SMALL LETTER Y WITH GRAVE */
- XK_Wdiaeresis = 0x1001e84, /* U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS */
- XK_wdiaeresis = 0x1001e85, /* U+1E85 LATIN SMALL LETTER W WITH DIAERESIS */
- XK_sabovedot = 0x1001e61, /* U+1E61 LATIN SMALL LETTER S WITH DOT ABOVE */
- XK_Wcircumflex = 0x1000174, /* U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
- XK_Tabovedot = 0x1001e6a, /* U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE */
- XK_Ycircumflex = 0x1000176, /* U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
- XK_wcircumflex = 0x1000175, /* U+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX */
- XK_tabovedot = 0x1001e6b, /* U+1E6B LATIN SMALL LETTER T WITH DOT ABOVE */
- XK_ycircumflex = 0x1000177, /* U+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX */
- XK_OE = 0x13bc, /* U+0152 LATIN CAPITAL LIGATURE OE */
- XK_oe = 0x13bd, /* U+0153 LATIN SMALL LIGATURE OE */
- XK_Ydiaeresis = 0x13be, /* U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS */
- XK_overline = 0x047e, /* U+203E OVERLINE */
- XK_kana_fullstop = 0x04a1, /* U+3002 IDEOGRAPHIC FULL STOP */
- XK_kana_openingbracket = 0x04a2, /* U+300C LEFT CORNER BRACKET */
- XK_kana_closingbracket = 0x04a3, /* U+300D RIGHT CORNER BRACKET */
- XK_kana_comma = 0x04a4, /* U+3001 IDEOGRAPHIC COMMA */
- XK_kana_conjunctive = 0x04a5, /* U+30FB KATAKANA MIDDLE DOT */
- XK_kana_middledot = 0x04a5, /* deprecated */
- XK_kana_WO = 0x04a6, /* U+30F2 KATAKANA LETTER WO */
- XK_kana_a = 0x04a7, /* U+30A1 KATAKANA LETTER SMALL A */
- XK_kana_i = 0x04a8, /* U+30A3 KATAKANA LETTER SMALL I */
- XK_kana_u = 0x04a9, /* U+30A5 KATAKANA LETTER SMALL U */
- XK_kana_e = 0x04aa, /* U+30A7 KATAKANA LETTER SMALL E */
- XK_kana_o = 0x04ab, /* U+30A9 KATAKANA LETTER SMALL O */
- XK_kana_ya = 0x04ac, /* U+30E3 KATAKANA LETTER SMALL YA */
- XK_kana_yu = 0x04ad, /* U+30E5 KATAKANA LETTER SMALL YU */
- XK_kana_yo = 0x04ae, /* U+30E7 KATAKANA LETTER SMALL YO */
- XK_kana_tsu = 0x04af, /* U+30C3 KATAKANA LETTER SMALL TU */
- XK_kana_tu = 0x04af, /* deprecated */
- XK_prolongedsound = 0x04b0, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */
- XK_kana_A = 0x04b1, /* U+30A2 KATAKANA LETTER A */
- XK_kana_I = 0x04b2, /* U+30A4 KATAKANA LETTER I */
- XK_kana_U = 0x04b3, /* U+30A6 KATAKANA LETTER U */
- XK_kana_E = 0x04b4, /* U+30A8 KATAKANA LETTER E */
- XK_kana_O = 0x04b5, /* U+30AA KATAKANA LETTER O */
- XK_kana_KA = 0x04b6, /* U+30AB KATAKANA LETTER KA */
- XK_kana_KI = 0x04b7, /* U+30AD KATAKANA LETTER KI */
- XK_kana_KU = 0x04b8, /* U+30AF KATAKANA LETTER KU */
- XK_kana_KE = 0x04b9, /* U+30B1 KATAKANA LETTER KE */
- XK_kana_KO = 0x04ba, /* U+30B3 KATAKANA LETTER KO */
- XK_kana_SA = 0x04bb, /* U+30B5 KATAKANA LETTER SA */
- XK_kana_SHI = 0x04bc, /* U+30B7 KATAKANA LETTER SI */
- XK_kana_SU = 0x04bd, /* U+30B9 KATAKANA LETTER SU */
- XK_kana_SE = 0x04be, /* U+30BB KATAKANA LETTER SE */
- XK_kana_SO = 0x04bf, /* U+30BD KATAKANA LETTER SO */
- XK_kana_TA = 0x04c0, /* U+30BF KATAKANA LETTER TA */
- XK_kana_CHI = 0x04c1, /* U+30C1 KATAKANA LETTER TI */
- XK_kana_TI = 0x04c1, /* deprecated */
- XK_kana_TSU = 0x04c2, /* U+30C4 KATAKANA LETTER TU */
- XK_kana_TU = 0x04c2, /* deprecated */
- XK_kana_TE = 0x04c3, /* U+30C6 KATAKANA LETTER TE */
- XK_kana_TO = 0x04c4, /* U+30C8 KATAKANA LETTER TO */
- XK_kana_NA = 0x04c5, /* U+30CA KATAKANA LETTER NA */
- XK_kana_NI = 0x04c6, /* U+30CB KATAKANA LETTER NI */
- XK_kana_NU = 0x04c7, /* U+30CC KATAKANA LETTER NU */
- XK_kana_NE = 0x04c8, /* U+30CD KATAKANA LETTER NE */
- XK_kana_NO = 0x04c9, /* U+30CE KATAKANA LETTER NO */
- XK_kana_HA = 0x04ca, /* U+30CF KATAKANA LETTER HA */
- XK_kana_HI = 0x04cb, /* U+30D2 KATAKANA LETTER HI */
- XK_kana_FU = 0x04cc, /* U+30D5 KATAKANA LETTER HU */
- XK_kana_HU = 0x04cc, /* deprecated */
- XK_kana_HE = 0x04cd, /* U+30D8 KATAKANA LETTER HE */
- XK_kana_HO = 0x04ce, /* U+30DB KATAKANA LETTER HO */
- XK_kana_MA = 0x04cf, /* U+30DE KATAKANA LETTER MA */
- XK_kana_MI = 0x04d0, /* U+30DF KATAKANA LETTER MI */
- XK_kana_MU = 0x04d1, /* U+30E0 KATAKANA LETTER MU */
- XK_kana_ME = 0x04d2, /* U+30E1 KATAKANA LETTER ME */
- XK_kana_MO = 0x04d3, /* U+30E2 KATAKANA LETTER MO */
- XK_kana_YA = 0x04d4, /* U+30E4 KATAKANA LETTER YA */
- XK_kana_YU = 0x04d5, /* U+30E6 KATAKANA LETTER YU */
- XK_kana_YO = 0x04d6, /* U+30E8 KATAKANA LETTER YO */
- XK_kana_RA = 0x04d7, /* U+30E9 KATAKANA LETTER RA */
- XK_kana_RI = 0x04d8, /* U+30EA KATAKANA LETTER RI */
- XK_kana_RU = 0x04d9, /* U+30EB KATAKANA LETTER RU */
- XK_kana_RE = 0x04da, /* U+30EC KATAKANA LETTER RE */
- XK_kana_RO = 0x04db, /* U+30ED KATAKANA LETTER RO */
- XK_kana_WA = 0x04dc, /* U+30EF KATAKANA LETTER WA */
- XK_kana_N = 0x04dd, /* U+30F3 KATAKANA LETTER N */
- XK_voicedsound = 0x04de, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */
- XK_semivoicedsound = 0x04df, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
- XK_kana_switch = 0xff7e, /* Alias for mode_switch */
- XK_Farsi_0 = 0x10006f0, /* U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO */
- XK_Farsi_1 = 0x10006f1, /* U+06F1 EXTENDED ARABIC-INDIC DIGIT ONE */
- XK_Farsi_2 = 0x10006f2, /* U+06F2 EXTENDED ARABIC-INDIC DIGIT TWO */
- XK_Farsi_3 = 0x10006f3, /* U+06F3 EXTENDED ARABIC-INDIC DIGIT THREE */
- XK_Farsi_4 = 0x10006f4, /* U+06F4 EXTENDED ARABIC-INDIC DIGIT FOUR */
- XK_Farsi_5 = 0x10006f5, /* U+06F5 EXTENDED ARABIC-INDIC DIGIT FIVE */
- XK_Farsi_6 = 0x10006f6, /* U+06F6 EXTENDED ARABIC-INDIC DIGIT SIX */
- XK_Farsi_7 = 0x10006f7, /* U+06F7 EXTENDED ARABIC-INDIC DIGIT SEVEN */
- XK_Farsi_8 = 0x10006f8, /* U+06F8 EXTENDED ARABIC-INDIC DIGIT EIGHT */
- XK_Farsi_9 = 0x10006f9, /* U+06F9 EXTENDED ARABIC-INDIC DIGIT NINE */
- XK_Arabic_percent = 0x100066a, /* U+066A ARABIC PERCENT SIGN */
- XK_Arabic_superscript_alef = 0x1000670, /* U+0670 ARABIC LETTER SUPERSCRIPT ALEF */
- XK_Arabic_tteh = 0x1000679, /* U+0679 ARABIC LETTER TTEH */
- XK_Arabic_peh = 0x100067e, /* U+067E ARABIC LETTER PEH */
- XK_Arabic_tcheh = 0x1000686, /* U+0686 ARABIC LETTER TCHEH */
- XK_Arabic_ddal = 0x1000688, /* U+0688 ARABIC LETTER DDAL */
- XK_Arabic_rreh = 0x1000691, /* U+0691 ARABIC LETTER RREH */
- XK_Arabic_comma = 0x05ac, /* U+060C ARABIC COMMA */
- XK_Arabic_fullstop = 0x10006d4, /* U+06D4 ARABIC FULL STOP */
- XK_Arabic_0 = 0x1000660, /* U+0660 ARABIC-INDIC DIGIT ZERO */
- XK_Arabic_1 = 0x1000661, /* U+0661 ARABIC-INDIC DIGIT ONE */
- XK_Arabic_2 = 0x1000662, /* U+0662 ARABIC-INDIC DIGIT TWO */
- XK_Arabic_3 = 0x1000663, /* U+0663 ARABIC-INDIC DIGIT THREE */
- XK_Arabic_4 = 0x1000664, /* U+0664 ARABIC-INDIC DIGIT FOUR */
- XK_Arabic_5 = 0x1000665, /* U+0665 ARABIC-INDIC DIGIT FIVE */
- XK_Arabic_6 = 0x1000666, /* U+0666 ARABIC-INDIC DIGIT SIX */
- XK_Arabic_7 = 0x1000667, /* U+0667 ARABIC-INDIC DIGIT SEVEN */
- XK_Arabic_8 = 0x1000668, /* U+0668 ARABIC-INDIC DIGIT EIGHT */
- XK_Arabic_9 = 0x1000669, /* U+0669 ARABIC-INDIC DIGIT NINE */
- XK_Arabic_semicolon = 0x05bb, /* U+061B ARABIC SEMICOLON */
- XK_Arabic_question_mark = 0x05bf, /* U+061F ARABIC QUESTION MARK */
- XK_Arabic_hamza = 0x05c1, /* U+0621 ARABIC LETTER HAMZA */
- XK_Arabic_maddaonalef = 0x05c2, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
- XK_Arabic_hamzaonalef = 0x05c3, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
- XK_Arabic_hamzaonwaw = 0x05c4, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
- XK_Arabic_hamzaunderalef = 0x05c5, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
- XK_Arabic_hamzaonyeh = 0x05c6, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
- XK_Arabic_alef = 0x05c7, /* U+0627 ARABIC LETTER ALEF */
- XK_Arabic_beh = 0x05c8, /* U+0628 ARABIC LETTER BEH */
- XK_Arabic_tehmarbuta = 0x05c9, /* U+0629 ARABIC LETTER TEH MARBUTA */
- XK_Arabic_teh = 0x05ca, /* U+062A ARABIC LETTER TEH */
- XK_Arabic_theh = 0x05cb, /* U+062B ARABIC LETTER THEH */
- XK_Arabic_jeem = 0x05cc, /* U+062C ARABIC LETTER JEEM */
- XK_Arabic_hah = 0x05cd, /* U+062D ARABIC LETTER HAH */
- XK_Arabic_khah = 0x05ce, /* U+062E ARABIC LETTER KHAH */
- XK_Arabic_dal = 0x05cf, /* U+062F ARABIC LETTER DAL */
- XK_Arabic_thal = 0x05d0, /* U+0630 ARABIC LETTER THAL */
- XK_Arabic_ra = 0x05d1, /* U+0631 ARABIC LETTER REH */
- XK_Arabic_zain = 0x05d2, /* U+0632 ARABIC LETTER ZAIN */
- XK_Arabic_seen = 0x05d3, /* U+0633 ARABIC LETTER SEEN */
- XK_Arabic_sheen = 0x05d4, /* U+0634 ARABIC LETTER SHEEN */
- XK_Arabic_sad = 0x05d5, /* U+0635 ARABIC LETTER SAD */
- XK_Arabic_dad = 0x05d6, /* U+0636 ARABIC LETTER DAD */
- XK_Arabic_tah = 0x05d7, /* U+0637 ARABIC LETTER TAH */
- XK_Arabic_zah = 0x05d8, /* U+0638 ARABIC LETTER ZAH */
- XK_Arabic_ain = 0x05d9, /* U+0639 ARABIC LETTER AIN */
- XK_Arabic_ghain = 0x05da, /* U+063A ARABIC LETTER GHAIN */
- XK_Arabic_tatweel = 0x05e0, /* U+0640 ARABIC TATWEEL */
- XK_Arabic_feh = 0x05e1, /* U+0641 ARABIC LETTER FEH */
- XK_Arabic_qaf = 0x05e2, /* U+0642 ARABIC LETTER QAF */
- XK_Arabic_kaf = 0x05e3, /* U+0643 ARABIC LETTER KAF */
- XK_Arabic_lam = 0x05e4, /* U+0644 ARABIC LETTER LAM */
- XK_Arabic_meem = 0x05e5, /* U+0645 ARABIC LETTER MEEM */
- XK_Arabic_noon = 0x05e6, /* U+0646 ARABIC LETTER NOON */
- XK_Arabic_ha = 0x05e7, /* U+0647 ARABIC LETTER HEH */
- XK_Arabic_heh = 0x05e7, /* deprecated */
- XK_Arabic_waw = 0x05e8, /* U+0648 ARABIC LETTER WAW */
- XK_Arabic_alefmaksura = 0x05e9, /* U+0649 ARABIC LETTER ALEF MAKSURA */
- XK_Arabic_yeh = 0x05ea, /* U+064A ARABIC LETTER YEH */
- XK_Arabic_fathatan = 0x05eb, /* U+064B ARABIC FATHATAN */
- XK_Arabic_dammatan = 0x05ec, /* U+064C ARABIC DAMMATAN */
- XK_Arabic_kasratan = 0x05ed, /* U+064D ARABIC KASRATAN */
- XK_Arabic_fatha = 0x05ee, /* U+064E ARABIC FATHA */
- XK_Arabic_damma = 0x05ef, /* U+064F ARABIC DAMMA */
- XK_Arabic_kasra = 0x05f0, /* U+0650 ARABIC KASRA */
- XK_Arabic_shadda = 0x05f1, /* U+0651 ARABIC SHADDA */
- XK_Arabic_sukun = 0x05f2, /* U+0652 ARABIC SUKUN */
- XK_Arabic_madda_above = 0x1000653, /* U+0653 ARABIC MADDAH ABOVE */
- XK_Arabic_hamza_above = 0x1000654, /* U+0654 ARABIC HAMZA ABOVE */
- XK_Arabic_hamza_below = 0x1000655, /* U+0655 ARABIC HAMZA BELOW */
- XK_Arabic_jeh = 0x1000698, /* U+0698 ARABIC LETTER JEH */
- XK_Arabic_veh = 0x10006a4, /* U+06A4 ARABIC LETTER VEH */
- XK_Arabic_keheh = 0x10006a9, /* U+06A9 ARABIC LETTER KEHEH */
- XK_Arabic_gaf = 0x10006af, /* U+06AF ARABIC LETTER GAF */
- XK_Arabic_noon_ghunna = 0x10006ba, /* U+06BA ARABIC LETTER NOON GHUNNA */
- XK_Arabic_heh_doachashmee = 0x10006be, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
- XK_Farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */
- XK_Arabic_farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */
- XK_Arabic_yeh_baree = 0x10006d2, /* U+06D2 ARABIC LETTER YEH BARREE */
- XK_Arabic_heh_goal = 0x10006c1, /* U+06C1 ARABIC LETTER HEH GOAL */
- XK_Arabic_switch = 0xff7e, /* Alias for mode_switch */
- XK_Cyrillic_GHE_bar = 0x1000492, /* U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE */
- XK_Cyrillic_ghe_bar = 0x1000493, /* U+0493 CYRILLIC SMALL LETTER GHE WITH STROKE */
- XK_Cyrillic_ZHE_descender = 0x1000496, /* U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */
- XK_Cyrillic_zhe_descender = 0x1000497, /* U+0497 CYRILLIC SMALL LETTER ZHE WITH DESCENDER */
- XK_Cyrillic_KA_descender = 0x100049a, /* U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER */
- XK_Cyrillic_ka_descender = 0x100049b, /* U+049B CYRILLIC SMALL LETTER KA WITH DESCENDER */
- XK_Cyrillic_KA_vertstroke = 0x100049c, /* U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */
- XK_Cyrillic_ka_vertstroke = 0x100049d, /* U+049D CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */
- XK_Cyrillic_EN_descender = 0x10004a2, /* U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER */
- XK_Cyrillic_en_descender = 0x10004a3, /* U+04A3 CYRILLIC SMALL LETTER EN WITH DESCENDER */
- XK_Cyrillic_U_straight = 0x10004ae, /* U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U */
- XK_Cyrillic_u_straight = 0x10004af, /* U+04AF CYRILLIC SMALL LETTER STRAIGHT U */
- XK_Cyrillic_U_straight_bar = 0x10004b0, /* U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */
- XK_Cyrillic_u_straight_bar = 0x10004b1, /* U+04B1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */
- XK_Cyrillic_HA_descender = 0x10004b2, /* U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER */
- XK_Cyrillic_ha_descender = 0x10004b3, /* U+04B3 CYRILLIC SMALL LETTER HA WITH DESCENDER */
- XK_Cyrillic_CHE_descender = 0x10004b6, /* U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */
- XK_Cyrillic_che_descender = 0x10004b7, /* U+04B7 CYRILLIC SMALL LETTER CHE WITH DESCENDER */
- XK_Cyrillic_CHE_vertstroke = 0x10004b8, /* U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */
- XK_Cyrillic_che_vertstroke = 0x10004b9, /* U+04B9 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */
- XK_Cyrillic_SHHA = 0x10004ba, /* U+04BA CYRILLIC CAPITAL LETTER SHHA */
- XK_Cyrillic_shha = 0x10004bb, /* U+04BB CYRILLIC SMALL LETTER SHHA */
- XK_Cyrillic_SCHWA = 0x10004d8, /* U+04D8 CYRILLIC CAPITAL LETTER SCHWA */
- XK_Cyrillic_schwa = 0x10004d9, /* U+04D9 CYRILLIC SMALL LETTER SCHWA */
- XK_Cyrillic_I_macron = 0x10004e2, /* U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON */
- XK_Cyrillic_i_macron = 0x10004e3, /* U+04E3 CYRILLIC SMALL LETTER I WITH MACRON */
- XK_Cyrillic_O_bar = 0x10004e8, /* U+04E8 CYRILLIC CAPITAL LETTER BARRED O */
- XK_Cyrillic_o_bar = 0x10004e9, /* U+04E9 CYRILLIC SMALL LETTER BARRED O */
- XK_Cyrillic_U_macron = 0x10004ee, /* U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON */
- XK_Cyrillic_u_macron = 0x10004ef, /* U+04EF CYRILLIC SMALL LETTER U WITH MACRON */
- XK_Serbian_dje = 0x06a1, /* U+0452 CYRILLIC SMALL LETTER DJE */
- XK_Macedonia_gje = 0x06a2, /* U+0453 CYRILLIC SMALL LETTER GJE */
- XK_Cyrillic_io = 0x06a3, /* U+0451 CYRILLIC SMALL LETTER IO */
- XK_Ukrainian_ie = 0x06a4, /* U+0454 CYRILLIC SMALL LETTER UKRAINIAN IE */
- XK_Ukranian_je = 0x06a4, /* deprecated */
- XK_Macedonia_dse = 0x06a5, /* U+0455 CYRILLIC SMALL LETTER DZE */
- XK_Ukrainian_i = 0x06a6, /* U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
- XK_Ukranian_i = 0x06a6, /* deprecated */
- XK_Ukrainian_yi = 0x06a7, /* U+0457 CYRILLIC SMALL LETTER YI */
- XK_Ukranian_yi = 0x06a7, /* deprecated */
- XK_Cyrillic_je = 0x06a8, /* U+0458 CYRILLIC SMALL LETTER JE */
- XK_Serbian_je = 0x06a8, /* deprecated */
- XK_Cyrillic_lje = 0x06a9, /* U+0459 CYRILLIC SMALL LETTER LJE */
- XK_Serbian_lje = 0x06a9, /* deprecated */
- XK_Cyrillic_nje = 0x06aa, /* U+045A CYRILLIC SMALL LETTER NJE */
- XK_Serbian_nje = 0x06aa, /* deprecated */
- XK_Serbian_tshe = 0x06ab, /* U+045B CYRILLIC SMALL LETTER TSHE */
- XK_Macedonia_kje = 0x06ac, /* U+045C CYRILLIC SMALL LETTER KJE */
- XK_Ukrainian_ghe_with_upturn = 0x06ad, /* U+0491 CYRILLIC SMALL LETTER GHE WITH UPTURN */
- XK_Byelorussian_shortu = 0x06ae, /* U+045E CYRILLIC SMALL LETTER SHORT U */
- XK_Cyrillic_dzhe = 0x06af, /* U+045F CYRILLIC SMALL LETTER DZHE */
- XK_Serbian_dze = 0x06af, /* deprecated */
- XK_numerosign = 0x06b0, /* U+2116 NUMERO SIGN */
- XK_Serbian_DJE = 0x06b1, /* U+0402 CYRILLIC CAPITAL LETTER DJE */
- XK_Macedonia_GJE = 0x06b2, /* U+0403 CYRILLIC CAPITAL LETTER GJE */
- XK_Cyrillic_IO = 0x06b3, /* U+0401 CYRILLIC CAPITAL LETTER IO */
- XK_Ukrainian_IE = 0x06b4, /* U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE */
- XK_Ukranian_JE = 0x06b4, /* deprecated */
- XK_Macedonia_DSE = 0x06b5, /* U+0405 CYRILLIC CAPITAL LETTER DZE */
- XK_Ukrainian_I = 0x06b6, /* U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
- XK_Ukranian_I = 0x06b6, /* deprecated */
- XK_Ukrainian_YI = 0x06b7, /* U+0407 CYRILLIC CAPITAL LETTER YI */
- XK_Ukranian_YI = 0x06b7, /* deprecated */
- XK_Cyrillic_JE = 0x06b8, /* U+0408 CYRILLIC CAPITAL LETTER JE */
- XK_Serbian_JE = 0x06b8, /* deprecated */
- XK_Cyrillic_LJE = 0x06b9, /* U+0409 CYRILLIC CAPITAL LETTER LJE */
- XK_Serbian_LJE = 0x06b9, /* deprecated */
- XK_Cyrillic_NJE = 0x06ba, /* U+040A CYRILLIC CAPITAL LETTER NJE */
- XK_Serbian_NJE = 0x06ba, /* deprecated */
- XK_Serbian_TSHE = 0x06bb, /* U+040B CYRILLIC CAPITAL LETTER TSHE */
- XK_Macedonia_KJE = 0x06bc, /* U+040C CYRILLIC CAPITAL LETTER KJE */
- XK_Ukrainian_GHE_WITH_UPTURN = 0x06bd, /* U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
- XK_Byelorussian_SHORTU = 0x06be, /* U+040E CYRILLIC CAPITAL LETTER SHORT U */
- XK_Cyrillic_DZHE = 0x06bf, /* U+040F CYRILLIC CAPITAL LETTER DZHE */
- XK_Serbian_DZE = 0x06bf, /* deprecated */
- XK_Cyrillic_yu = 0x06c0, /* U+044E CYRILLIC SMALL LETTER YU */
- XK_Cyrillic_a = 0x06c1, /* U+0430 CYRILLIC SMALL LETTER A */
- XK_Cyrillic_be = 0x06c2, /* U+0431 CYRILLIC SMALL LETTER BE */
- XK_Cyrillic_tse = 0x06c3, /* U+0446 CYRILLIC SMALL LETTER TSE */
- XK_Cyrillic_de = 0x06c4, /* U+0434 CYRILLIC SMALL LETTER DE */
- XK_Cyrillic_ie = 0x06c5, /* U+0435 CYRILLIC SMALL LETTER IE */
- XK_Cyrillic_ef = 0x06c6, /* U+0444 CYRILLIC SMALL LETTER EF */
- XK_Cyrillic_ghe = 0x06c7, /* U+0433 CYRILLIC SMALL LETTER GHE */
- XK_Cyrillic_ha = 0x06c8, /* U+0445 CYRILLIC SMALL LETTER HA */
- XK_Cyrillic_i = 0x06c9, /* U+0438 CYRILLIC SMALL LETTER I */
- XK_Cyrillic_shorti = 0x06ca, /* U+0439 CYRILLIC SMALL LETTER SHORT I */
- XK_Cyrillic_ka = 0x06cb, /* U+043A CYRILLIC SMALL LETTER KA */
- XK_Cyrillic_el = 0x06cc, /* U+043B CYRILLIC SMALL LETTER EL */
- XK_Cyrillic_em = 0x06cd, /* U+043C CYRILLIC SMALL LETTER EM */
- XK_Cyrillic_en = 0x06ce, /* U+043D CYRILLIC SMALL LETTER EN */
- XK_Cyrillic_o = 0x06cf, /* U+043E CYRILLIC SMALL LETTER O */
- XK_Cyrillic_pe = 0x06d0, /* U+043F CYRILLIC SMALL LETTER PE */
- XK_Cyrillic_ya = 0x06d1, /* U+044F CYRILLIC SMALL LETTER YA */
- XK_Cyrillic_er = 0x06d2, /* U+0440 CYRILLIC SMALL LETTER ER */
- XK_Cyrillic_es = 0x06d3, /* U+0441 CYRILLIC SMALL LETTER ES */
- XK_Cyrillic_te = 0x06d4, /* U+0442 CYRILLIC SMALL LETTER TE */
- XK_Cyrillic_u = 0x06d5, /* U+0443 CYRILLIC SMALL LETTER U */
- XK_Cyrillic_zhe = 0x06d6, /* U+0436 CYRILLIC SMALL LETTER ZHE */
- XK_Cyrillic_ve = 0x06d7, /* U+0432 CYRILLIC SMALL LETTER VE */
- XK_Cyrillic_softsign = 0x06d8, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */
- XK_Cyrillic_yeru = 0x06d9, /* U+044B CYRILLIC SMALL LETTER YERU */
- XK_Cyrillic_ze = 0x06da, /* U+0437 CYRILLIC SMALL LETTER ZE */
- XK_Cyrillic_sha = 0x06db, /* U+0448 CYRILLIC SMALL LETTER SHA */
- XK_Cyrillic_e = 0x06dc, /* U+044D CYRILLIC SMALL LETTER E */
- XK_Cyrillic_shcha = 0x06dd, /* U+0449 CYRILLIC SMALL LETTER SHCHA */
- XK_Cyrillic_che = 0x06de, /* U+0447 CYRILLIC SMALL LETTER CHE */
- XK_Cyrillic_hardsign = 0x06df, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */
- XK_Cyrillic_YU = 0x06e0, /* U+042E CYRILLIC CAPITAL LETTER YU */
- XK_Cyrillic_A = 0x06e1, /* U+0410 CYRILLIC CAPITAL LETTER A */
- XK_Cyrillic_BE = 0x06e2, /* U+0411 CYRILLIC CAPITAL LETTER BE */
- XK_Cyrillic_TSE = 0x06e3, /* U+0426 CYRILLIC CAPITAL LETTER TSE */
- XK_Cyrillic_DE = 0x06e4, /* U+0414 CYRILLIC CAPITAL LETTER DE */
- XK_Cyrillic_IE = 0x06e5, /* U+0415 CYRILLIC CAPITAL LETTER IE */
- XK_Cyrillic_EF = 0x06e6, /* U+0424 CYRILLIC CAPITAL LETTER EF */
- XK_Cyrillic_GHE = 0x06e7, /* U+0413 CYRILLIC CAPITAL LETTER GHE */
- XK_Cyrillic_HA = 0x06e8, /* U+0425 CYRILLIC CAPITAL LETTER HA */
- XK_Cyrillic_I = 0x06e9, /* U+0418 CYRILLIC CAPITAL LETTER I */
- XK_Cyrillic_SHORTI = 0x06ea, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */
- XK_Cyrillic_KA = 0x06eb, /* U+041A CYRILLIC CAPITAL LETTER KA */
- XK_Cyrillic_EL = 0x06ec, /* U+041B CYRILLIC CAPITAL LETTER EL */
- XK_Cyrillic_EM = 0x06ed, /* U+041C CYRILLIC CAPITAL LETTER EM */
- XK_Cyrillic_EN = 0x06ee, /* U+041D CYRILLIC CAPITAL LETTER EN */
- XK_Cyrillic_O = 0x06ef, /* U+041E CYRILLIC CAPITAL LETTER O */
- XK_Cyrillic_PE = 0x06f0, /* U+041F CYRILLIC CAPITAL LETTER PE */
- XK_Cyrillic_YA = 0x06f1, /* U+042F CYRILLIC CAPITAL LETTER YA */
- XK_Cyrillic_ER = 0x06f2, /* U+0420 CYRILLIC CAPITAL LETTER ER */
- XK_Cyrillic_ES = 0x06f3, /* U+0421 CYRILLIC CAPITAL LETTER ES */
- XK_Cyrillic_TE = 0x06f4, /* U+0422 CYRILLIC CAPITAL LETTER TE */
- XK_Cyrillic_U = 0x06f5, /* U+0423 CYRILLIC CAPITAL LETTER U */
- XK_Cyrillic_ZHE = 0x06f6, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */
- XK_Cyrillic_VE = 0x06f7, /* U+0412 CYRILLIC CAPITAL LETTER VE */
- XK_Cyrillic_SOFTSIGN = 0x06f8, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */
- XK_Cyrillic_YERU = 0x06f9, /* U+042B CYRILLIC CAPITAL LETTER YERU */
- XK_Cyrillic_ZE = 0x06fa, /* U+0417 CYRILLIC CAPITAL LETTER ZE */
- XK_Cyrillic_SHA = 0x06fb, /* U+0428 CYRILLIC CAPITAL LETTER SHA */
- XK_Cyrillic_E = 0x06fc, /* U+042D CYRILLIC CAPITAL LETTER E */
- XK_Cyrillic_SHCHA = 0x06fd, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */
- XK_Cyrillic_CHE = 0x06fe, /* U+0427 CYRILLIC CAPITAL LETTER CHE */
- XK_Cyrillic_HARDSIGN = 0x06ff, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */
- XK_Greek_ALPHAaccent = 0x07a1, /* U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS */
- XK_Greek_EPSILONaccent = 0x07a2, /* U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS */
- XK_Greek_ETAaccent = 0x07a3, /* U+0389 GREEK CAPITAL LETTER ETA WITH TONOS */
- XK_Greek_IOTAaccent = 0x07a4, /* U+038A GREEK CAPITAL LETTER IOTA WITH TONOS */
- XK_Greek_IOTAdieresis = 0x07a5, /* U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
- XK_Greek_IOTAdiaeresis = 0x07a5, /* old typo */
- XK_Greek_OMICRONaccent = 0x07a7, /* U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS */
- XK_Greek_UPSILONaccent = 0x07a8, /* U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS */
- XK_Greek_UPSILONdieresis = 0x07a9, /* U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
- XK_Greek_OMEGAaccent = 0x07ab, /* U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS */
- XK_Greek_accentdieresis = 0x07ae, /* U+0385 GREEK DIALYTIKA TONOS */
- XK_Greek_horizbar = 0x07af, /* U+2015 HORIZONTAL BAR */
- XK_Greek_alphaaccent = 0x07b1, /* U+03AC GREEK SMALL LETTER ALPHA WITH TONOS */
- XK_Greek_epsilonaccent = 0x07b2, /* U+03AD GREEK SMALL LETTER EPSILON WITH TONOS */
- XK_Greek_etaaccent = 0x07b3, /* U+03AE GREEK SMALL LETTER ETA WITH TONOS */
- XK_Greek_iotaaccent = 0x07b4, /* U+03AF GREEK SMALL LETTER IOTA WITH TONOS */
- XK_Greek_iotadieresis = 0x07b5, /* U+03CA GREEK SMALL LETTER IOTA WITH DIALYTIKA */
- XK_Greek_iotaaccentdieresis = 0x07b6, /* U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
- XK_Greek_omicronaccent = 0x07b7, /* U+03CC GREEK SMALL LETTER OMICRON WITH TONOS */
- XK_Greek_upsilonaccent = 0x07b8, /* U+03CD GREEK SMALL LETTER UPSILON WITH TONOS */
- XK_Greek_upsilondieresis = 0x07b9, /* U+03CB GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
- XK_Greek_upsilonaccentdieresis = 0x07ba, /* U+03B0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
- XK_Greek_omegaaccent = 0x07bb, /* U+03CE GREEK SMALL LETTER OMEGA WITH TONOS */
- XK_Greek_ALPHA = 0x07c1, /* U+0391 GREEK CAPITAL LETTER ALPHA */
- XK_Greek_BETA = 0x07c2, /* U+0392 GREEK CAPITAL LETTER BETA */
- XK_Greek_GAMMA = 0x07c3, /* U+0393 GREEK CAPITAL LETTER GAMMA */
- XK_Greek_DELTA = 0x07c4, /* U+0394 GREEK CAPITAL LETTER DELTA */
- XK_Greek_EPSILON = 0x07c5, /* U+0395 GREEK CAPITAL LETTER EPSILON */
- XK_Greek_ZETA = 0x07c6, /* U+0396 GREEK CAPITAL LETTER ZETA */
- XK_Greek_ETA = 0x07c7, /* U+0397 GREEK CAPITAL LETTER ETA */
- XK_Greek_THETA = 0x07c8, /* U+0398 GREEK CAPITAL LETTER THETA */
- XK_Greek_IOTA = 0x07c9, /* U+0399 GREEK CAPITAL LETTER IOTA */
- XK_Greek_KAPPA = 0x07ca, /* U+039A GREEK CAPITAL LETTER KAPPA */
- XK_Greek_LAMDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */
- XK_Greek_LAMBDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */
- XK_Greek_MU = 0x07cc, /* U+039C GREEK CAPITAL LETTER MU */
- XK_Greek_NU = 0x07cd, /* U+039D GREEK CAPITAL LETTER NU */
- XK_Greek_XI = 0x07ce, /* U+039E GREEK CAPITAL LETTER XI */
- XK_Greek_OMICRON = 0x07cf, /* U+039F GREEK CAPITAL LETTER OMICRON */
- XK_Greek_PI = 0x07d0, /* U+03A0 GREEK CAPITAL LETTER PI */
- XK_Greek_RHO = 0x07d1, /* U+03A1 GREEK CAPITAL LETTER RHO */
- XK_Greek_SIGMA = 0x07d2, /* U+03A3 GREEK CAPITAL LETTER SIGMA */
- XK_Greek_TAU = 0x07d4, /* U+03A4 GREEK CAPITAL LETTER TAU */
- XK_Greek_UPSILON = 0x07d5, /* U+03A5 GREEK CAPITAL LETTER UPSILON */
- XK_Greek_PHI = 0x07d6, /* U+03A6 GREEK CAPITAL LETTER PHI */
- XK_Greek_CHI = 0x07d7, /* U+03A7 GREEK CAPITAL LETTER CHI */
- XK_Greek_PSI = 0x07d8, /* U+03A8 GREEK CAPITAL LETTER PSI */
- XK_Greek_OMEGA = 0x07d9, /* U+03A9 GREEK CAPITAL LETTER OMEGA */
- XK_Greek_alpha = 0x07e1, /* U+03B1 GREEK SMALL LETTER ALPHA */
- XK_Greek_beta = 0x07e2, /* U+03B2 GREEK SMALL LETTER BETA */
- XK_Greek_gamma = 0x07e3, /* U+03B3 GREEK SMALL LETTER GAMMA */
- XK_Greek_delta = 0x07e4, /* U+03B4 GREEK SMALL LETTER DELTA */
- XK_Greek_epsilon = 0x07e5, /* U+03B5 GREEK SMALL LETTER EPSILON */
- XK_Greek_zeta = 0x07e6, /* U+03B6 GREEK SMALL LETTER ZETA */
- XK_Greek_eta = 0x07e7, /* U+03B7 GREEK SMALL LETTER ETA */
- XK_Greek_theta = 0x07e8, /* U+03B8 GREEK SMALL LETTER THETA */
- XK_Greek_iota = 0x07e9, /* U+03B9 GREEK SMALL LETTER IOTA */
- XK_Greek_kappa = 0x07ea, /* U+03BA GREEK SMALL LETTER KAPPA */
- XK_Greek_lamda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */
- XK_Greek_lambda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */
- XK_Greek_mu = 0x07ec, /* U+03BC GREEK SMALL LETTER MU */
- XK_Greek_nu = 0x07ed, /* U+03BD GREEK SMALL LETTER NU */
- XK_Greek_xi = 0x07ee, /* U+03BE GREEK SMALL LETTER XI */
- XK_Greek_omicron = 0x07ef, /* U+03BF GREEK SMALL LETTER OMICRON */
- XK_Greek_pi = 0x07f0, /* U+03C0 GREEK SMALL LETTER PI */
- XK_Greek_rho = 0x07f1, /* U+03C1 GREEK SMALL LETTER RHO */
- XK_Greek_sigma = 0x07f2, /* U+03C3 GREEK SMALL LETTER SIGMA */
- XK_Greek_finalsmallsigma = 0x07f3, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA */
- XK_Greek_tau = 0x07f4, /* U+03C4 GREEK SMALL LETTER TAU */
- XK_Greek_upsilon = 0x07f5, /* U+03C5 GREEK SMALL LETTER UPSILON */
- XK_Greek_phi = 0x07f6, /* U+03C6 GREEK SMALL LETTER PHI */
- XK_Greek_chi = 0x07f7, /* U+03C7 GREEK SMALL LETTER CHI */
- XK_Greek_psi = 0x07f8, /* U+03C8 GREEK SMALL LETTER PSI */
- XK_Greek_omega = 0x07f9, /* U+03C9 GREEK SMALL LETTER OMEGA */
- XK_Greek_switch = 0xff7e, /* Alias for mode_switch */
- XK_leftradical = 0x08a1, /* U+23B7 RADICAL SYMBOL BOTTOM */
- XK_topleftradical = 0x08a2, /*(U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT)*/
- XK_horizconnector = 0x08a3, /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/
- XK_topintegral = 0x08a4, /* U+2320 TOP HALF INTEGRAL */
- XK_botintegral = 0x08a5, /* U+2321 BOTTOM HALF INTEGRAL */
- XK_vertconnector = 0x08a6, /*(U+2502 BOX DRAWINGS LIGHT VERTICAL)*/
- XK_topleftsqbracket = 0x08a7, /* U+23A1 LEFT SQUARE BRACKET UPPER CORNER */
- XK_botleftsqbracket = 0x08a8, /* U+23A3 LEFT SQUARE BRACKET LOWER CORNER */
- XK_toprightsqbracket = 0x08a9, /* U+23A4 RIGHT SQUARE BRACKET UPPER CORNER */
- XK_botrightsqbracket = 0x08aa, /* U+23A6 RIGHT SQUARE BRACKET LOWER CORNER */
- XK_topleftparens = 0x08ab, /* U+239B LEFT PARENTHESIS UPPER HOOK */
- XK_botleftparens = 0x08ac, /* U+239D LEFT PARENTHESIS LOWER HOOK */
- XK_toprightparens = 0x08ad, /* U+239E RIGHT PARENTHESIS UPPER HOOK */
- XK_botrightparens = 0x08ae, /* U+23A0 RIGHT PARENTHESIS LOWER HOOK */
- XK_leftmiddlecurlybrace = 0x08af, /* U+23A8 LEFT CURLY BRACKET MIDDLE PIECE */
- XK_rightmiddlecurlybrace = 0x08b0, /* U+23AC RIGHT CURLY BRACKET MIDDLE PIECE */
- XK_topleftsummation = 0x08b1,
- XK_botleftsummation = 0x08b2,
- XK_topvertsummationconnector = 0x08b3,
- XK_botvertsummationconnector = 0x08b4,
- XK_toprightsummation = 0x08b5,
- XK_botrightsummation = 0x08b6,
- XK_rightmiddlesummation = 0x08b7,
- XK_lessthanequal = 0x08bc, /* U+2264 LESS-THAN OR EQUAL TO */
- XK_notequal = 0x08bd, /* U+2260 NOT EQUAL TO */
- XK_greaterthanequal = 0x08be, /* U+2265 GREATER-THAN OR EQUAL TO */
- XK_integral = 0x08bf, /* U+222B INTEGRAL */
- XK_therefore = 0x08c0, /* U+2234 THEREFORE */
- XK_variation = 0x08c1, /* U+221D PROPORTIONAL TO */
- XK_infinity = 0x08c2, /* U+221E INFINITY */
- XK_nabla = 0x08c5, /* U+2207 NABLA */
- XK_approximate = 0x08c8, /* U+223C TILDE OPERATOR */
- XK_similarequal = 0x08c9, /* U+2243 ASYMPTOTICALLY EQUAL TO */
- XK_ifonlyif = 0x08cd, /* U+21D4 LEFT RIGHT DOUBLE ARROW */
- XK_implies = 0x08ce, /* U+21D2 RIGHTWARDS DOUBLE ARROW */
- XK_identical = 0x08cf, /* U+2261 IDENTICAL TO */
- XK_radical = 0x08d6, /* U+221A SQUARE ROOT */
- XK_includedin = 0x08da, /* U+2282 SUBSET OF */
- XK_includes = 0x08db, /* U+2283 SUPERSET OF */
- XK_intersection = 0x08dc, /* U+2229 INTERSECTION */
- XK_union = 0x08dd, /* U+222A UNION */
- XK_logicaland = 0x08de, /* U+2227 LOGICAL AND */
- XK_logicalor = 0x08df, /* U+2228 LOGICAL OR */
- XK_partialderivative = 0x08ef, /* U+2202 PARTIAL DIFFERENTIAL */
- XK_function = 0x08f6, /* U+0192 LATIN SMALL LETTER F WITH HOOK */
- XK_leftarrow = 0x08fb, /* U+2190 LEFTWARDS ARROW */
- XK_uparrow = 0x08fc, /* U+2191 UPWARDS ARROW */
- XK_rightarrow = 0x08fd, /* U+2192 RIGHTWARDS ARROW */
- XK_downarrow = 0x08fe, /* U+2193 DOWNWARDS ARROW */
- XK_blank = 0x09df,
- XK_soliddiamond = 0x09e0, /* U+25C6 BLACK DIAMOND */
- XK_checkerboard = 0x09e1, /* U+2592 MEDIUM SHADE */
- XK_ht = 0x09e2, /* U+2409 SYMBOL FOR HORIZONTAL TABULATION */
- XK_ff = 0x09e3, /* U+240C SYMBOL FOR FORM FEED */
- XK_cr = 0x09e4, /* U+240D SYMBOL FOR CARRIAGE RETURN */
- XK_lf = 0x09e5, /* U+240A SYMBOL FOR LINE FEED */
- XK_nl = 0x09e8, /* U+2424 SYMBOL FOR NEWLINE */
- XK_vt = 0x09e9, /* U+240B SYMBOL FOR VERTICAL TABULATION */
- XK_lowrightcorner = 0x09ea, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */
- XK_uprightcorner = 0x09eb, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */
- XK_upleftcorner = 0x09ec, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */
- XK_lowleftcorner = 0x09ed, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */
- XK_crossinglines = 0x09ee, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
- XK_horizlinescan1 = 0x09ef, /* U+23BA HORIZONTAL SCAN LINE-1 */
- XK_horizlinescan3 = 0x09f0, /* U+23BB HORIZONTAL SCAN LINE-3 */
- XK_horizlinescan5 = 0x09f1, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */
- XK_horizlinescan7 = 0x09f2, /* U+23BC HORIZONTAL SCAN LINE-7 */
- XK_horizlinescan9 = 0x09f3, /* U+23BD HORIZONTAL SCAN LINE-9 */
- XK_leftt = 0x09f4, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
- XK_rightt = 0x09f5, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */
- XK_bott = 0x09f6, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */
- XK_topt = 0x09f7, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
- XK_vertbar = 0x09f8, /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
- XK_emspace = 0x0aa1, /* U+2003 EM SPACE */
- XK_enspace = 0x0aa2, /* U+2002 EN SPACE */
- XK_em3space = 0x0aa3, /* U+2004 THREE-PER-EM SPACE */
- XK_em4space = 0x0aa4, /* U+2005 FOUR-PER-EM SPACE */
- XK_digitspace = 0x0aa5, /* U+2007 FIGURE SPACE */
- XK_punctspace = 0x0aa6, /* U+2008 PUNCTUATION SPACE */
- XK_thinspace = 0x0aa7, /* U+2009 THIN SPACE */
- XK_hairspace = 0x0aa8, /* U+200A HAIR SPACE */
- XK_emdash = 0x0aa9, /* U+2014 EM DASH */
- XK_endash = 0x0aaa, /* U+2013 EN DASH */
- XK_signifblank = 0x0aac, /*(U+2423 OPEN BOX)*/
- XK_ellipsis = 0x0aae, /* U+2026 HORIZONTAL ELLIPSIS */
- XK_doubbaselinedot = 0x0aaf, /* U+2025 TWO DOT LEADER */
- XK_onethird = 0x0ab0, /* U+2153 VULGAR FRACTION ONE THIRD */
- XK_twothirds = 0x0ab1, /* U+2154 VULGAR FRACTION TWO THIRDS */
- XK_onefifth = 0x0ab2, /* U+2155 VULGAR FRACTION ONE FIFTH */
- XK_twofifths = 0x0ab3, /* U+2156 VULGAR FRACTION TWO FIFTHS */
- XK_threefifths = 0x0ab4, /* U+2157 VULGAR FRACTION THREE FIFTHS */
- XK_fourfifths = 0x0ab5, /* U+2158 VULGAR FRACTION FOUR FIFTHS */
- XK_onesixth = 0x0ab6, /* U+2159 VULGAR FRACTION ONE SIXTH */
- XK_fivesixths = 0x0ab7, /* U+215A VULGAR FRACTION FIVE SIXTHS */
- XK_careof = 0x0ab8, /* U+2105 CARE OF */
- XK_figdash = 0x0abb, /* U+2012 FIGURE DASH */
- XK_leftanglebracket = 0x0abc, /*(U+27E8 MATHEMATICAL LEFT ANGLE BRACKET)*/
- XK_decimalpoint = 0x0abd, /*(U+002E FULL STOP)*/
- XK_rightanglebracket = 0x0abe, /*(U+27E9 MATHEMATICAL RIGHT ANGLE BRACKET)*/
- XK_marker = 0x0abf,
- XK_oneeighth = 0x0ac3, /* U+215B VULGAR FRACTION ONE EIGHTH */
- XK_threeeighths = 0x0ac4, /* U+215C VULGAR FRACTION THREE EIGHTHS */
- XK_fiveeighths = 0x0ac5, /* U+215D VULGAR FRACTION FIVE EIGHTHS */
- XK_seveneighths = 0x0ac6, /* U+215E VULGAR FRACTION SEVEN EIGHTHS */
- XK_trademark = 0x0ac9, /* U+2122 TRADE MARK SIGN */
- XK_signaturemark = 0x0aca, /*(U+2613 SALTIRE)*/
- XK_trademarkincircle = 0x0acb,
- XK_leftopentriangle = 0x0acc, /*(U+25C1 WHITE LEFT-POINTING TRIANGLE)*/
- XK_rightopentriangle = 0x0acd, /*(U+25B7 WHITE RIGHT-POINTING TRIANGLE)*/
- XK_emopencircle = 0x0ace, /*(U+25CB WHITE CIRCLE)*/
- XK_emopenrectangle = 0x0acf, /*(U+25AF WHITE VERTICAL RECTANGLE)*/
- XK_leftsinglequotemark = 0x0ad0, /* U+2018 LEFT SINGLE QUOTATION MARK */
- XK_rightsinglequotemark = 0x0ad1, /* U+2019 RIGHT SINGLE QUOTATION MARK */
- XK_leftdoublequotemark = 0x0ad2, /* U+201C LEFT DOUBLE QUOTATION MARK */
- XK_rightdoublequotemark = 0x0ad3, /* U+201D RIGHT DOUBLE QUOTATION MARK */
- XK_prescription = 0x0ad4, /* U+211E PRESCRIPTION TAKE */
- XK_minutes = 0x0ad6, /* U+2032 PRIME */
- XK_seconds = 0x0ad7, /* U+2033 DOUBLE PRIME */
- XK_latincross = 0x0ad9, /* U+271D LATIN CROSS */
- XK_hexagram = 0x0ada,
- XK_filledrectbullet = 0x0adb, /*(U+25AC BLACK RECTANGLE)*/
- XK_filledlefttribullet = 0x0adc, /*(U+25C0 BLACK LEFT-POINTING TRIANGLE)*/
- XK_filledrighttribullet = 0x0add, /*(U+25B6 BLACK RIGHT-POINTING TRIANGLE)*/
- XK_emfilledcircle = 0x0ade, /*(U+25CF BLACK CIRCLE)*/
- XK_emfilledrect = 0x0adf, /*(U+25AE BLACK VERTICAL RECTANGLE)*/
- XK_enopencircbullet = 0x0ae0, /*(U+25E6 WHITE BULLET)*/
- XK_enopensquarebullet = 0x0ae1, /*(U+25AB WHITE SMALL SQUARE)*/
- XK_openrectbullet = 0x0ae2, /*(U+25AD WHITE RECTANGLE)*/
- XK_opentribulletup = 0x0ae3, /*(U+25B3 WHITE UP-POINTING TRIANGLE)*/
- XK_opentribulletdown = 0x0ae4, /*(U+25BD WHITE DOWN-POINTING TRIANGLE)*/
- XK_openstar = 0x0ae5, /*(U+2606 WHITE STAR)*/
- XK_enfilledcircbullet = 0x0ae6, /*(U+2022 BULLET)*/
- XK_enfilledsqbullet = 0x0ae7, /*(U+25AA BLACK SMALL SQUARE)*/
- XK_filledtribulletup = 0x0ae8, /*(U+25B2 BLACK UP-POINTING TRIANGLE)*/
- XK_filledtribulletdown = 0x0ae9, /*(U+25BC BLACK DOWN-POINTING TRIANGLE)*/
- XK_leftpointer = 0x0aea, /*(U+261C WHITE LEFT POINTING INDEX)*/
- XK_rightpointer = 0x0aeb, /*(U+261E WHITE RIGHT POINTING INDEX)*/
- XK_club = 0x0aec, /* U+2663 BLACK CLUB SUIT */
- XK_diamond = 0x0aed, /* U+2666 BLACK DIAMOND SUIT */
- XK_heart = 0x0aee, /* U+2665 BLACK HEART SUIT */
- XK_maltesecross = 0x0af0, /* U+2720 MALTESE CROSS */
- XK_dagger = 0x0af1, /* U+2020 DAGGER */
- XK_doubledagger = 0x0af2, /* U+2021 DOUBLE DAGGER */
- XK_checkmark = 0x0af3, /* U+2713 CHECK MARK */
- XK_ballotcross = 0x0af4, /* U+2717 BALLOT X */
- XK_musicalsharp = 0x0af5, /* U+266F MUSIC SHARP SIGN */
- XK_musicalflat = 0x0af6, /* U+266D MUSIC FLAT SIGN */
- XK_malesymbol = 0x0af7, /* U+2642 MALE SIGN */
- XK_femalesymbol = 0x0af8, /* U+2640 FEMALE SIGN */
- XK_telephone = 0x0af9, /* U+260E BLACK TELEPHONE */
- XK_telephonerecorder = 0x0afa, /* U+2315 TELEPHONE RECORDER */
- XK_phonographcopyright = 0x0afb, /* U+2117 SOUND RECORDING COPYRIGHT */
- XK_caret = 0x0afc, /* U+2038 CARET */
- XK_singlelowquotemark = 0x0afd, /* U+201A SINGLE LOW-9 QUOTATION MARK */
- XK_doublelowquotemark = 0x0afe, /* U+201E DOUBLE LOW-9 QUOTATION MARK */
- XK_cursor = 0x0aff,
- XK_leftcaret = 0x0ba3, /*(U+003C LESS-THAN SIGN)*/
- XK_rightcaret = 0x0ba6, /*(U+003E GREATER-THAN SIGN)*/
- XK_downcaret = 0x0ba8, /*(U+2228 LOGICAL OR)*/
- XK_upcaret = 0x0ba9, /*(U+2227 LOGICAL AND)*/
- XK_overbar = 0x0bc0, /*(U+00AF MACRON)*/
- XK_downtack = 0x0bc2, /* U+22A5 UP TACK */
- XK_upshoe = 0x0bc3, /*(U+2229 INTERSECTION)*/
- XK_downstile = 0x0bc4, /* U+230A LEFT FLOOR */
- XK_underbar = 0x0bc6, /*(U+005F LOW LINE)*/
- XK_jot = 0x0bca, /* U+2218 RING OPERATOR */
- XK_quad = 0x0bcc, /* U+2395 APL FUNCTIONAL SYMBOL QUAD */
- XK_uptack = 0x0bce, /* U+22A4 DOWN TACK */
- XK_circle = 0x0bcf, /* U+25CB WHITE CIRCLE */
- XK_upstile = 0x0bd3, /* U+2308 LEFT CEILING */
- XK_downshoe = 0x0bd6, /*(U+222A UNION)*/
- XK_rightshoe = 0x0bd8, /*(U+2283 SUPERSET OF)*/
- XK_leftshoe = 0x0bda, /*(U+2282 SUBSET OF)*/
- XK_lefttack = 0x0bdc, /* U+22A2 RIGHT TACK */
- XK_righttack = 0x0bfc, /* U+22A3 LEFT TACK */
- XK_hebrew_doublelowline = 0x0cdf, /* U+2017 DOUBLE LOW LINE */
- XK_hebrew_aleph = 0x0ce0, /* U+05D0 HEBREW LETTER ALEF */
- XK_hebrew_bet = 0x0ce1, /* U+05D1 HEBREW LETTER BET */
- XK_hebrew_beth = 0x0ce1, /* deprecated */
- XK_hebrew_gimel = 0x0ce2, /* U+05D2 HEBREW LETTER GIMEL */
- XK_hebrew_gimmel = 0x0ce2, /* deprecated */
- XK_hebrew_dalet = 0x0ce3, /* U+05D3 HEBREW LETTER DALET */
- XK_hebrew_daleth = 0x0ce3, /* deprecated */
- XK_hebrew_he = 0x0ce4, /* U+05D4 HEBREW LETTER HE */
- XK_hebrew_waw = 0x0ce5, /* U+05D5 HEBREW LETTER VAV */
- XK_hebrew_zain = 0x0ce6, /* U+05D6 HEBREW LETTER ZAYIN */
- XK_hebrew_zayin = 0x0ce6, /* deprecated */
- XK_hebrew_chet = 0x0ce7, /* U+05D7 HEBREW LETTER HET */
- XK_hebrew_het = 0x0ce7, /* deprecated */
- XK_hebrew_tet = 0x0ce8, /* U+05D8 HEBREW LETTER TET */
- XK_hebrew_teth = 0x0ce8, /* deprecated */
- XK_hebrew_yod = 0x0ce9, /* U+05D9 HEBREW LETTER YOD */
- XK_hebrew_finalkaph = 0x0cea, /* U+05DA HEBREW LETTER FINAL KAF */
- XK_hebrew_kaph = 0x0ceb, /* U+05DB HEBREW LETTER KAF */
- XK_hebrew_lamed = 0x0cec, /* U+05DC HEBREW LETTER LAMED */
- XK_hebrew_finalmem = 0x0ced, /* U+05DD HEBREW LETTER FINAL MEM */
- XK_hebrew_mem = 0x0cee, /* U+05DE HEBREW LETTER MEM */
- XK_hebrew_finalnun = 0x0cef, /* U+05DF HEBREW LETTER FINAL NUN */
- XK_hebrew_nun = 0x0cf0, /* U+05E0 HEBREW LETTER NUN */
- XK_hebrew_samech = 0x0cf1, /* U+05E1 HEBREW LETTER SAMEKH */
- XK_hebrew_samekh = 0x0cf1, /* deprecated */
- XK_hebrew_ayin = 0x0cf2, /* U+05E2 HEBREW LETTER AYIN */
- XK_hebrew_finalpe = 0x0cf3, /* U+05E3 HEBREW LETTER FINAL PE */
- XK_hebrew_pe = 0x0cf4, /* U+05E4 HEBREW LETTER PE */
- XK_hebrew_finalzade = 0x0cf5, /* U+05E5 HEBREW LETTER FINAL TSADI */
- XK_hebrew_finalzadi = 0x0cf5, /* deprecated */
- XK_hebrew_zade = 0x0cf6, /* U+05E6 HEBREW LETTER TSADI */
- XK_hebrew_zadi = 0x0cf6, /* deprecated */
- XK_hebrew_qoph = 0x0cf7, /* U+05E7 HEBREW LETTER QOF */
- XK_hebrew_kuf = 0x0cf7, /* deprecated */
- XK_hebrew_resh = 0x0cf8, /* U+05E8 HEBREW LETTER RESH */
- XK_hebrew_shin = 0x0cf9, /* U+05E9 HEBREW LETTER SHIN */
- XK_hebrew_taw = 0x0cfa, /* U+05EA HEBREW LETTER TAV */
- XK_hebrew_taf = 0x0cfa, /* deprecated */
- XK_Hebrew_switch = 0xff7e, /* Alias for mode_switch */
- XK_Thai_kokai = 0x0da1, /* U+0E01 THAI CHARACTER KO KAI */
- XK_Thai_khokhai = 0x0da2, /* U+0E02 THAI CHARACTER KHO KHAI */
- XK_Thai_khokhuat = 0x0da3, /* U+0E03 THAI CHARACTER KHO KHUAT */
- XK_Thai_khokhwai = 0x0da4, /* U+0E04 THAI CHARACTER KHO KHWAI */
- XK_Thai_khokhon = 0x0da5, /* U+0E05 THAI CHARACTER KHO KHON */
- XK_Thai_khorakhang = 0x0da6, /* U+0E06 THAI CHARACTER KHO RAKHANG */
- XK_Thai_ngongu = 0x0da7, /* U+0E07 THAI CHARACTER NGO NGU */
- XK_Thai_chochan = 0x0da8, /* U+0E08 THAI CHARACTER CHO CHAN */
- XK_Thai_choching = 0x0da9, /* U+0E09 THAI CHARACTER CHO CHING */
- XK_Thai_chochang = 0x0daa, /* U+0E0A THAI CHARACTER CHO CHANG */
- XK_Thai_soso = 0x0dab, /* U+0E0B THAI CHARACTER SO SO */
- XK_Thai_chochoe = 0x0dac, /* U+0E0C THAI CHARACTER CHO CHOE */
- XK_Thai_yoying = 0x0dad, /* U+0E0D THAI CHARACTER YO YING */
- XK_Thai_dochada = 0x0dae, /* U+0E0E THAI CHARACTER DO CHADA */
- XK_Thai_topatak = 0x0daf, /* U+0E0F THAI CHARACTER TO PATAK */
- XK_Thai_thothan = 0x0db0, /* U+0E10 THAI CHARACTER THO THAN */
- XK_Thai_thonangmontho = 0x0db1, /* U+0E11 THAI CHARACTER THO NANGMONTHO */
- XK_Thai_thophuthao = 0x0db2, /* U+0E12 THAI CHARACTER THO PHUTHAO */
- XK_Thai_nonen = 0x0db3, /* U+0E13 THAI CHARACTER NO NEN */
- XK_Thai_dodek = 0x0db4, /* U+0E14 THAI CHARACTER DO DEK */
- XK_Thai_totao = 0x0db5, /* U+0E15 THAI CHARACTER TO TAO */
- XK_Thai_thothung = 0x0db6, /* U+0E16 THAI CHARACTER THO THUNG */
- XK_Thai_thothahan = 0x0db7, /* U+0E17 THAI CHARACTER THO THAHAN */
- XK_Thai_thothong = 0x0db8, /* U+0E18 THAI CHARACTER THO THONG */
- XK_Thai_nonu = 0x0db9, /* U+0E19 THAI CHARACTER NO NU */
- XK_Thai_bobaimai = 0x0dba, /* U+0E1A THAI CHARACTER BO BAIMAI */
- XK_Thai_popla = 0x0dbb, /* U+0E1B THAI CHARACTER PO PLA */
- XK_Thai_phophung = 0x0dbc, /* U+0E1C THAI CHARACTER PHO PHUNG */
- XK_Thai_fofa = 0x0dbd, /* U+0E1D THAI CHARACTER FO FA */
- XK_Thai_phophan = 0x0dbe, /* U+0E1E THAI CHARACTER PHO PHAN */
- XK_Thai_fofan = 0x0dbf, /* U+0E1F THAI CHARACTER FO FAN */
- XK_Thai_phosamphao = 0x0dc0, /* U+0E20 THAI CHARACTER PHO SAMPHAO */
- XK_Thai_moma = 0x0dc1, /* U+0E21 THAI CHARACTER MO MA */
- XK_Thai_yoyak = 0x0dc2, /* U+0E22 THAI CHARACTER YO YAK */
- XK_Thai_rorua = 0x0dc3, /* U+0E23 THAI CHARACTER RO RUA */
- XK_Thai_ru = 0x0dc4, /* U+0E24 THAI CHARACTER RU */
- XK_Thai_loling = 0x0dc5, /* U+0E25 THAI CHARACTER LO LING */
- XK_Thai_lu = 0x0dc6, /* U+0E26 THAI CHARACTER LU */
- XK_Thai_wowaen = 0x0dc7, /* U+0E27 THAI CHARACTER WO WAEN */
- XK_Thai_sosala = 0x0dc8, /* U+0E28 THAI CHARACTER SO SALA */
- XK_Thai_sorusi = 0x0dc9, /* U+0E29 THAI CHARACTER SO RUSI */
- XK_Thai_sosua = 0x0dca, /* U+0E2A THAI CHARACTER SO SUA */
- XK_Thai_hohip = 0x0dcb, /* U+0E2B THAI CHARACTER HO HIP */
- XK_Thai_lochula = 0x0dcc, /* U+0E2C THAI CHARACTER LO CHULA */
- XK_Thai_oang = 0x0dcd, /* U+0E2D THAI CHARACTER O ANG */
- XK_Thai_honokhuk = 0x0dce, /* U+0E2E THAI CHARACTER HO NOKHUK */
- XK_Thai_paiyannoi = 0x0dcf, /* U+0E2F THAI CHARACTER PAIYANNOI */
- XK_Thai_saraa = 0x0dd0, /* U+0E30 THAI CHARACTER SARA A */
- XK_Thai_maihanakat = 0x0dd1, /* U+0E31 THAI CHARACTER MAI HAN-AKAT */
- XK_Thai_saraaa = 0x0dd2, /* U+0E32 THAI CHARACTER SARA AA */
- XK_Thai_saraam = 0x0dd3, /* U+0E33 THAI CHARACTER SARA AM */
- XK_Thai_sarai = 0x0dd4, /* U+0E34 THAI CHARACTER SARA I */
- XK_Thai_saraii = 0x0dd5, /* U+0E35 THAI CHARACTER SARA II */
- XK_Thai_saraue = 0x0dd6, /* U+0E36 THAI CHARACTER SARA UE */
- XK_Thai_sarauee = 0x0dd7, /* U+0E37 THAI CHARACTER SARA UEE */
- XK_Thai_sarau = 0x0dd8, /* U+0E38 THAI CHARACTER SARA U */
- XK_Thai_sarauu = 0x0dd9, /* U+0E39 THAI CHARACTER SARA UU */
- XK_Thai_phinthu = 0x0dda, /* U+0E3A THAI CHARACTER PHINTHU */
- XK_Thai_maihanakat_maitho = 0x0dde,
- XK_Thai_baht = 0x0ddf, /* U+0E3F THAI CURRENCY SYMBOL BAHT */
- XK_Thai_sarae = 0x0de0, /* U+0E40 THAI CHARACTER SARA E */
- XK_Thai_saraae = 0x0de1, /* U+0E41 THAI CHARACTER SARA AE */
- XK_Thai_sarao = 0x0de2, /* U+0E42 THAI CHARACTER SARA O */
- XK_Thai_saraaimaimuan = 0x0de3, /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */
- XK_Thai_saraaimaimalai = 0x0de4, /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */
- XK_Thai_lakkhangyao = 0x0de5, /* U+0E45 THAI CHARACTER LAKKHANGYAO */
- XK_Thai_maiyamok = 0x0de6, /* U+0E46 THAI CHARACTER MAIYAMOK */
- XK_Thai_maitaikhu = 0x0de7, /* U+0E47 THAI CHARACTER MAITAIKHU */
- XK_Thai_maiek = 0x0de8, /* U+0E48 THAI CHARACTER MAI EK */
- XK_Thai_maitho = 0x0de9, /* U+0E49 THAI CHARACTER MAI THO */
- XK_Thai_maitri = 0x0dea, /* U+0E4A THAI CHARACTER MAI TRI */
- XK_Thai_maichattawa = 0x0deb, /* U+0E4B THAI CHARACTER MAI CHATTAWA */
- XK_Thai_thanthakhat = 0x0dec, /* U+0E4C THAI CHARACTER THANTHAKHAT */
- XK_Thai_nikhahit = 0x0ded, /* U+0E4D THAI CHARACTER NIKHAHIT */
- XK_Thai_leksun = 0x0df0, /* U+0E50 THAI DIGIT ZERO */
- XK_Thai_leknung = 0x0df1, /* U+0E51 THAI DIGIT ONE */
- XK_Thai_leksong = 0x0df2, /* U+0E52 THAI DIGIT TWO */
- XK_Thai_leksam = 0x0df3, /* U+0E53 THAI DIGIT THREE */
- XK_Thai_leksi = 0x0df4, /* U+0E54 THAI DIGIT FOUR */
- XK_Thai_lekha = 0x0df5, /* U+0E55 THAI DIGIT FIVE */
- XK_Thai_lekhok = 0x0df6, /* U+0E56 THAI DIGIT SIX */
- XK_Thai_lekchet = 0x0df7, /* U+0E57 THAI DIGIT SEVEN */
- XK_Thai_lekpaet = 0x0df8, /* U+0E58 THAI DIGIT EIGHT */
- XK_Thai_lekkao = 0x0df9, /* U+0E59 THAI DIGIT NINE */
- XK_Hangul = 0xff31, /* Hangul start/stop(toggle) */
- XK_Hangul_Start = 0xff32, /* Hangul start */
- XK_Hangul_End = 0xff33, /* Hangul end, English start */
- XK_Hangul_Hanja = 0xff34, /* Start Hangul->Hanja Conversion */
- XK_Hangul_Jamo = 0xff35, /* Hangul Jamo mode */
- XK_Hangul_Romaja = 0xff36, /* Hangul Romaja mode */
- XK_Hangul_Codeinput = 0xff37, /* Hangul code input mode */
- XK_Hangul_Jeonja = 0xff38, /* Jeonja mode */
- XK_Hangul_Banja = 0xff39, /* Banja mode */
- XK_Hangul_PreHanja = 0xff3a, /* Pre Hanja conversion */
- XK_Hangul_PostHanja = 0xff3b, /* Post Hanja conversion */
- XK_Hangul_SingleCandidate = 0xff3c, /* Single candidate */
- XK_Hangul_MultipleCandidate = 0xff3d, /* Multiple candidate */
- XK_Hangul_PreviousCandidate = 0xff3e, /* Previous candidate */
- XK_Hangul_Special = 0xff3f, /* Special symbols */
- XK_Hangul_switch = 0xff7e, /* Alias for mode_switch */
- XK_Hangul_Kiyeog = 0x0ea1,
- XK_Hangul_SsangKiyeog = 0x0ea2,
- XK_Hangul_KiyeogSios = 0x0ea3,
- XK_Hangul_Nieun = 0x0ea4,
- XK_Hangul_NieunJieuj = 0x0ea5,
- XK_Hangul_NieunHieuh = 0x0ea6,
- XK_Hangul_Dikeud = 0x0ea7,
- XK_Hangul_SsangDikeud = 0x0ea8,
- XK_Hangul_Rieul = 0x0ea9,
- XK_Hangul_RieulKiyeog = 0x0eaa,
- XK_Hangul_RieulMieum = 0x0eab,
- XK_Hangul_RieulPieub = 0x0eac,
- XK_Hangul_RieulSios = 0x0ead,
- XK_Hangul_RieulTieut = 0x0eae,
- XK_Hangul_RieulPhieuf = 0x0eaf,
- XK_Hangul_RieulHieuh = 0x0eb0,
- XK_Hangul_Mieum = 0x0eb1,
- XK_Hangul_Pieub = 0x0eb2,
- XK_Hangul_SsangPieub = 0x0eb3,
- XK_Hangul_PieubSios = 0x0eb4,
- XK_Hangul_Sios = 0x0eb5,
- XK_Hangul_SsangSios = 0x0eb6,
- XK_Hangul_Ieung = 0x0eb7,
- XK_Hangul_Jieuj = 0x0eb8,
- XK_Hangul_SsangJieuj = 0x0eb9,
- XK_Hangul_Cieuc = 0x0eba,
- XK_Hangul_Khieuq = 0x0ebb,
- XK_Hangul_Tieut = 0x0ebc,
- XK_Hangul_Phieuf = 0x0ebd,
- XK_Hangul_Hieuh = 0x0ebe,
- XK_Hangul_A = 0x0ebf,
- XK_Hangul_AE = 0x0ec0,
- XK_Hangul_YA = 0x0ec1,
- XK_Hangul_YAE = 0x0ec2,
- XK_Hangul_EO = 0x0ec3,
- XK_Hangul_E = 0x0ec4,
- XK_Hangul_YEO = 0x0ec5,
- XK_Hangul_YE = 0x0ec6,
- XK_Hangul_O = 0x0ec7,
- XK_Hangul_WA = 0x0ec8,
- XK_Hangul_WAE = 0x0ec9,
- XK_Hangul_OE = 0x0eca,
- XK_Hangul_YO = 0x0ecb,
- XK_Hangul_U = 0x0ecc,
- XK_Hangul_WEO = 0x0ecd,
- XK_Hangul_WE = 0x0ece,
- XK_Hangul_WI = 0x0ecf,
- XK_Hangul_YU = 0x0ed0,
- XK_Hangul_EU = 0x0ed1,
- XK_Hangul_YI = 0x0ed2,
- XK_Hangul_I = 0x0ed3,
- XK_Hangul_J_Kiyeog = 0x0ed4,
- XK_Hangul_J_SsangKiyeog = 0x0ed5,
- XK_Hangul_J_KiyeogSios = 0x0ed6,
- XK_Hangul_J_Nieun = 0x0ed7,
- XK_Hangul_J_NieunJieuj = 0x0ed8,
- XK_Hangul_J_NieunHieuh = 0x0ed9,
- XK_Hangul_J_Dikeud = 0x0eda,
- XK_Hangul_J_Rieul = 0x0edb,
- XK_Hangul_J_RieulKiyeog = 0x0edc,
- XK_Hangul_J_RieulMieum = 0x0edd,
- XK_Hangul_J_RieulPieub = 0x0ede,
- XK_Hangul_J_RieulSios = 0x0edf,
- XK_Hangul_J_RieulTieut = 0x0ee0,
- XK_Hangul_J_RieulPhieuf = 0x0ee1,
- XK_Hangul_J_RieulHieuh = 0x0ee2,
- XK_Hangul_J_Mieum = 0x0ee3,
- XK_Hangul_J_Pieub = 0x0ee4,
- XK_Hangul_J_PieubSios = 0x0ee5,
- XK_Hangul_J_Sios = 0x0ee6,
- XK_Hangul_J_SsangSios = 0x0ee7,
- XK_Hangul_J_Ieung = 0x0ee8,
- XK_Hangul_J_Jieuj = 0x0ee9,
- XK_Hangul_J_Cieuc = 0x0eea,
- XK_Hangul_J_Khieuq = 0x0eeb,
- XK_Hangul_J_Tieut = 0x0eec,
- XK_Hangul_J_Phieuf = 0x0eed,
- XK_Hangul_J_Hieuh = 0x0eee,
- XK_Hangul_RieulYeorinHieuh = 0x0eef,
- XK_Hangul_SunkyeongeumMieum = 0x0ef0,
- XK_Hangul_SunkyeongeumPieub = 0x0ef1,
- XK_Hangul_PanSios = 0x0ef2,
- XK_Hangul_KkogjiDalrinIeung = 0x0ef3,
- XK_Hangul_SunkyeongeumPhieuf = 0x0ef4,
- XK_Hangul_YeorinHieuh = 0x0ef5,
- XK_Hangul_AraeA = 0x0ef6,
- XK_Hangul_AraeAE = 0x0ef7,
- XK_Hangul_J_PanSios = 0x0ef8,
- XK_Hangul_J_KkogjiDalrinIeung = 0x0ef9,
- XK_Hangul_J_YeorinHieuh = 0x0efa,
- XK_Korean_Won = 0x0eff, /*(U+20A9 WON SIGN)*/
- XK_Armenian_ligature_ew = 0x1000587, /* U+0587 ARMENIAN SMALL LIGATURE ECH YIWN */
- XK_Armenian_full_stop = 0x1000589, /* U+0589 ARMENIAN FULL STOP */
- XK_Armenian_verjaket = 0x1000589, /* U+0589 ARMENIAN FULL STOP */
- XK_Armenian_separation_mark = 0x100055d, /* U+055D ARMENIAN COMMA */
- XK_Armenian_but = 0x100055d, /* U+055D ARMENIAN COMMA */
- XK_Armenian_hyphen = 0x100058a, /* U+058A ARMENIAN HYPHEN */
- XK_Armenian_yentamna = 0x100058a, /* U+058A ARMENIAN HYPHEN */
- XK_Armenian_exclam = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */
- XK_Armenian_amanak = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */
- XK_Armenian_accent = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */
- XK_Armenian_shesht = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */
- XK_Armenian_question = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */
- XK_Armenian_paruyk = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */
- XK_Armenian_AYB = 0x1000531, /* U+0531 ARMENIAN CAPITAL LETTER AYB */
- XK_Armenian_ayb = 0x1000561, /* U+0561 ARMENIAN SMALL LETTER AYB */
- XK_Armenian_BEN = 0x1000532, /* U+0532 ARMENIAN CAPITAL LETTER BEN */
- XK_Armenian_ben = 0x1000562, /* U+0562 ARMENIAN SMALL LETTER BEN */
- XK_Armenian_GIM = 0x1000533, /* U+0533 ARMENIAN CAPITAL LETTER GIM */
- XK_Armenian_gim = 0x1000563, /* U+0563 ARMENIAN SMALL LETTER GIM */
- XK_Armenian_DA = 0x1000534, /* U+0534 ARMENIAN CAPITAL LETTER DA */
- XK_Armenian_da = 0x1000564, /* U+0564 ARMENIAN SMALL LETTER DA */
- XK_Armenian_YECH = 0x1000535, /* U+0535 ARMENIAN CAPITAL LETTER ECH */
- XK_Armenian_yech = 0x1000565, /* U+0565 ARMENIAN SMALL LETTER ECH */
- XK_Armenian_ZA = 0x1000536, /* U+0536 ARMENIAN CAPITAL LETTER ZA */
- XK_Armenian_za = 0x1000566, /* U+0566 ARMENIAN SMALL LETTER ZA */
- XK_Armenian_E = 0x1000537, /* U+0537 ARMENIAN CAPITAL LETTER EH */
- XK_Armenian_e = 0x1000567, /* U+0567 ARMENIAN SMALL LETTER EH */
- XK_Armenian_AT = 0x1000538, /* U+0538 ARMENIAN CAPITAL LETTER ET */
- XK_Armenian_at = 0x1000568, /* U+0568 ARMENIAN SMALL LETTER ET */
- XK_Armenian_TO = 0x1000539, /* U+0539 ARMENIAN CAPITAL LETTER TO */
- XK_Armenian_to = 0x1000569, /* U+0569 ARMENIAN SMALL LETTER TO */
- XK_Armenian_ZHE = 0x100053a, /* U+053A ARMENIAN CAPITAL LETTER ZHE */
- XK_Armenian_zhe = 0x100056a, /* U+056A ARMENIAN SMALL LETTER ZHE */
- XK_Armenian_INI = 0x100053b, /* U+053B ARMENIAN CAPITAL LETTER INI */
- XK_Armenian_ini = 0x100056b, /* U+056B ARMENIAN SMALL LETTER INI */
- XK_Armenian_LYUN = 0x100053c, /* U+053C ARMENIAN CAPITAL LETTER LIWN */
- XK_Armenian_lyun = 0x100056c, /* U+056C ARMENIAN SMALL LETTER LIWN */
- XK_Armenian_KHE = 0x100053d, /* U+053D ARMENIAN CAPITAL LETTER XEH */
- XK_Armenian_khe = 0x100056d, /* U+056D ARMENIAN SMALL LETTER XEH */
- XK_Armenian_TSA = 0x100053e, /* U+053E ARMENIAN CAPITAL LETTER CA */
- XK_Armenian_tsa = 0x100056e, /* U+056E ARMENIAN SMALL LETTER CA */
- XK_Armenian_KEN = 0x100053f, /* U+053F ARMENIAN CAPITAL LETTER KEN */
- XK_Armenian_ken = 0x100056f, /* U+056F ARMENIAN SMALL LETTER KEN */
- XK_Armenian_HO = 0x1000540, /* U+0540 ARMENIAN CAPITAL LETTER HO */
- XK_Armenian_ho = 0x1000570, /* U+0570 ARMENIAN SMALL LETTER HO */
- XK_Armenian_DZA = 0x1000541, /* U+0541 ARMENIAN CAPITAL LETTER JA */
- XK_Armenian_dza = 0x1000571, /* U+0571 ARMENIAN SMALL LETTER JA */
- XK_Armenian_GHAT = 0x1000542, /* U+0542 ARMENIAN CAPITAL LETTER GHAD */
- XK_Armenian_ghat = 0x1000572, /* U+0572 ARMENIAN SMALL LETTER GHAD */
- XK_Armenian_TCHE = 0x1000543, /* U+0543 ARMENIAN CAPITAL LETTER CHEH */
- XK_Armenian_tche = 0x1000573, /* U+0573 ARMENIAN SMALL LETTER CHEH */
- XK_Armenian_MEN = 0x1000544, /* U+0544 ARMENIAN CAPITAL LETTER MEN */
- XK_Armenian_men = 0x1000574, /* U+0574 ARMENIAN SMALL LETTER MEN */
- XK_Armenian_HI = 0x1000545, /* U+0545 ARMENIAN CAPITAL LETTER YI */
- XK_Armenian_hi = 0x1000575, /* U+0575 ARMENIAN SMALL LETTER YI */
- XK_Armenian_NU = 0x1000546, /* U+0546 ARMENIAN CAPITAL LETTER NOW */
- XK_Armenian_nu = 0x1000576, /* U+0576 ARMENIAN SMALL LETTER NOW */
- XK_Armenian_SHA = 0x1000547, /* U+0547 ARMENIAN CAPITAL LETTER SHA */
- XK_Armenian_sha = 0x1000577, /* U+0577 ARMENIAN SMALL LETTER SHA */
- XK_Armenian_VO = 0x1000548, /* U+0548 ARMENIAN CAPITAL LETTER VO */
- XK_Armenian_vo = 0x1000578, /* U+0578 ARMENIAN SMALL LETTER VO */
- XK_Armenian_CHA = 0x1000549, /* U+0549 ARMENIAN CAPITAL LETTER CHA */
- XK_Armenian_cha = 0x1000579, /* U+0579 ARMENIAN SMALL LETTER CHA */
- XK_Armenian_PE = 0x100054a, /* U+054A ARMENIAN CAPITAL LETTER PEH */
- XK_Armenian_pe = 0x100057a, /* U+057A ARMENIAN SMALL LETTER PEH */
- XK_Armenian_JE = 0x100054b, /* U+054B ARMENIAN CAPITAL LETTER JHEH */
- XK_Armenian_je = 0x100057b, /* U+057B ARMENIAN SMALL LETTER JHEH */
- XK_Armenian_RA = 0x100054c, /* U+054C ARMENIAN CAPITAL LETTER RA */
- XK_Armenian_ra = 0x100057c, /* U+057C ARMENIAN SMALL LETTER RA */
- XK_Armenian_SE = 0x100054d, /* U+054D ARMENIAN CAPITAL LETTER SEH */
- XK_Armenian_se = 0x100057d, /* U+057D ARMENIAN SMALL LETTER SEH */
- XK_Armenian_VEV = 0x100054e, /* U+054E ARMENIAN CAPITAL LETTER VEW */
- XK_Armenian_vev = 0x100057e, /* U+057E ARMENIAN SMALL LETTER VEW */
- XK_Armenian_TYUN = 0x100054f, /* U+054F ARMENIAN CAPITAL LETTER TIWN */
- XK_Armenian_tyun = 0x100057f, /* U+057F ARMENIAN SMALL LETTER TIWN */
- XK_Armenian_RE = 0x1000550, /* U+0550 ARMENIAN CAPITAL LETTER REH */
- XK_Armenian_re = 0x1000580, /* U+0580 ARMENIAN SMALL LETTER REH */
- XK_Armenian_TSO = 0x1000551, /* U+0551 ARMENIAN CAPITAL LETTER CO */
- XK_Armenian_tso = 0x1000581, /* U+0581 ARMENIAN SMALL LETTER CO */
- XK_Armenian_VYUN = 0x1000552, /* U+0552 ARMENIAN CAPITAL LETTER YIWN */
- XK_Armenian_vyun = 0x1000582, /* U+0582 ARMENIAN SMALL LETTER YIWN */
- XK_Armenian_PYUR = 0x1000553, /* U+0553 ARMENIAN CAPITAL LETTER PIWR */
- XK_Armenian_pyur = 0x1000583, /* U+0583 ARMENIAN SMALL LETTER PIWR */
- XK_Armenian_KE = 0x1000554, /* U+0554 ARMENIAN CAPITAL LETTER KEH */
- XK_Armenian_ke = 0x1000584, /* U+0584 ARMENIAN SMALL LETTER KEH */
- XK_Armenian_O = 0x1000555, /* U+0555 ARMENIAN CAPITAL LETTER OH */
- XK_Armenian_o = 0x1000585, /* U+0585 ARMENIAN SMALL LETTER OH */
- XK_Armenian_FE = 0x1000556, /* U+0556 ARMENIAN CAPITAL LETTER FEH */
- XK_Armenian_fe = 0x1000586, /* U+0586 ARMENIAN SMALL LETTER FEH */
- XK_Armenian_apostrophe = 0x100055a, /* U+055A ARMENIAN APOSTROPHE */
- XK_Georgian_an = 0x10010d0, /* U+10D0 GEORGIAN LETTER AN */
- XK_Georgian_ban = 0x10010d1, /* U+10D1 GEORGIAN LETTER BAN */
- XK_Georgian_gan = 0x10010d2, /* U+10D2 GEORGIAN LETTER GAN */
- XK_Georgian_don = 0x10010d3, /* U+10D3 GEORGIAN LETTER DON */
- XK_Georgian_en = 0x10010d4, /* U+10D4 GEORGIAN LETTER EN */
- XK_Georgian_vin = 0x10010d5, /* U+10D5 GEORGIAN LETTER VIN */
- XK_Georgian_zen = 0x10010d6, /* U+10D6 GEORGIAN LETTER ZEN */
- XK_Georgian_tan = 0x10010d7, /* U+10D7 GEORGIAN LETTER TAN */
- XK_Georgian_in = 0x10010d8, /* U+10D8 GEORGIAN LETTER IN */
- XK_Georgian_kan = 0x10010d9, /* U+10D9 GEORGIAN LETTER KAN */
- XK_Georgian_las = 0x10010da, /* U+10DA GEORGIAN LETTER LAS */
- XK_Georgian_man = 0x10010db, /* U+10DB GEORGIAN LETTER MAN */
- XK_Georgian_nar = 0x10010dc, /* U+10DC GEORGIAN LETTER NAR */
- XK_Georgian_on = 0x10010dd, /* U+10DD GEORGIAN LETTER ON */
- XK_Georgian_par = 0x10010de, /* U+10DE GEORGIAN LETTER PAR */
- XK_Georgian_zhar = 0x10010df, /* U+10DF GEORGIAN LETTER ZHAR */
- XK_Georgian_rae = 0x10010e0, /* U+10E0 GEORGIAN LETTER RAE */
- XK_Georgian_san = 0x10010e1, /* U+10E1 GEORGIAN LETTER SAN */
- XK_Georgian_tar = 0x10010e2, /* U+10E2 GEORGIAN LETTER TAR */
- XK_Georgian_un = 0x10010e3, /* U+10E3 GEORGIAN LETTER UN */
- XK_Georgian_phar = 0x10010e4, /* U+10E4 GEORGIAN LETTER PHAR */
- XK_Georgian_khar = 0x10010e5, /* U+10E5 GEORGIAN LETTER KHAR */
- XK_Georgian_ghan = 0x10010e6, /* U+10E6 GEORGIAN LETTER GHAN */
- XK_Georgian_qar = 0x10010e7, /* U+10E7 GEORGIAN LETTER QAR */
- XK_Georgian_shin = 0x10010e8, /* U+10E8 GEORGIAN LETTER SHIN */
- XK_Georgian_chin = 0x10010e9, /* U+10E9 GEORGIAN LETTER CHIN */
- XK_Georgian_can = 0x10010ea, /* U+10EA GEORGIAN LETTER CAN */
- XK_Georgian_jil = 0x10010eb, /* U+10EB GEORGIAN LETTER JIL */
- XK_Georgian_cil = 0x10010ec, /* U+10EC GEORGIAN LETTER CIL */
- XK_Georgian_char = 0x10010ed, /* U+10ED GEORGIAN LETTER CHAR */
- XK_Georgian_xan = 0x10010ee, /* U+10EE GEORGIAN LETTER XAN */
- XK_Georgian_jhan = 0x10010ef, /* U+10EF GEORGIAN LETTER JHAN */
- XK_Georgian_hae = 0x10010f0, /* U+10F0 GEORGIAN LETTER HAE */
- XK_Georgian_he = 0x10010f1, /* U+10F1 GEORGIAN LETTER HE */
- XK_Georgian_hie = 0x10010f2, /* U+10F2 GEORGIAN LETTER HIE */
- XK_Georgian_we = 0x10010f3, /* U+10F3 GEORGIAN LETTER WE */
- XK_Georgian_har = 0x10010f4, /* U+10F4 GEORGIAN LETTER HAR */
- XK_Georgian_hoe = 0x10010f5, /* U+10F5 GEORGIAN LETTER HOE */
- XK_Georgian_fi = 0x10010f6, /* U+10F6 GEORGIAN LETTER FI */
- XK_Xabovedot = 0x1001e8a, /* U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE */
- XK_Ibreve = 0x100012c, /* U+012C LATIN CAPITAL LETTER I WITH BREVE */
- XK_Zstroke = 0x10001b5, /* U+01B5 LATIN CAPITAL LETTER Z WITH STROKE */
- XK_Gcaron = 0x10001e6, /* U+01E6 LATIN CAPITAL LETTER G WITH CARON */
- XK_Ocaron = 0x10001d1, /* U+01D2 LATIN CAPITAL LETTER O WITH CARON */
- XK_Obarred = 0x100019f, /* U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE */
- XK_xabovedot = 0x1001e8b, /* U+1E8B LATIN SMALL LETTER X WITH DOT ABOVE */
- XK_ibreve = 0x100012d, /* U+012D LATIN SMALL LETTER I WITH BREVE */
- XK_zstroke = 0x10001b6, /* U+01B6 LATIN SMALL LETTER Z WITH STROKE */
- XK_gcaron = 0x10001e7, /* U+01E7 LATIN SMALL LETTER G WITH CARON */
- XK_ocaron = 0x10001d2, /* U+01D2 LATIN SMALL LETTER O WITH CARON */
- XK_obarred = 0x1000275, /* U+0275 LATIN SMALL LETTER BARRED O */
- XK_SCHWA = 0x100018f, /* U+018F LATIN CAPITAL LETTER SCHWA */
- XK_schwa = 0x1000259, /* U+0259 LATIN SMALL LETTER SCHWA */
- XK_Lbelowdot = 0x1001e36, /* U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW */
- XK_lbelowdot = 0x1001e37, /* U+1E37 LATIN SMALL LETTER L WITH DOT BELOW */
- XK_Abelowdot = 0x1001ea0, /* U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW */
- XK_abelowdot = 0x1001ea1, /* U+1EA1 LATIN SMALL LETTER A WITH DOT BELOW */
- XK_Ahook = 0x1001ea2, /* U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE */
- XK_ahook = 0x1001ea3, /* U+1EA3 LATIN SMALL LETTER A WITH HOOK ABOVE */
- XK_Acircumflexacute = 0x1001ea4, /* U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */
- XK_acircumflexacute = 0x1001ea5, /* U+1EA5 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */
- XK_Acircumflexgrave = 0x1001ea6, /* U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */
- XK_acircumflexgrave = 0x1001ea7, /* U+1EA7 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */
- XK_Acircumflexhook = 0x1001ea8, /* U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_acircumflexhook = 0x1001ea9, /* U+1EA9 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_Acircumflextilde = 0x1001eaa, /* U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */
- XK_acircumflextilde = 0x1001eab, /* U+1EAB LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */
- XK_Acircumflexbelowdot = 0x1001eac, /* U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
- XK_acircumflexbelowdot = 0x1001ead, /* U+1EAD LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
- XK_Abreveacute = 0x1001eae, /* U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */
- XK_abreveacute = 0x1001eaf, /* U+1EAF LATIN SMALL LETTER A WITH BREVE AND ACUTE */
- XK_Abrevegrave = 0x1001eb0, /* U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */
- XK_abrevegrave = 0x1001eb1, /* U+1EB1 LATIN SMALL LETTER A WITH BREVE AND GRAVE */
- XK_Abrevehook = 0x1001eb2, /* U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */
- XK_abrevehook = 0x1001eb3, /* U+1EB3 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */
- XK_Abrevetilde = 0x1001eb4, /* U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE */
- XK_abrevetilde = 0x1001eb5, /* U+1EB5 LATIN SMALL LETTER A WITH BREVE AND TILDE */
- XK_Abrevebelowdot = 0x1001eb6, /* U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */
- XK_abrevebelowdot = 0x1001eb7, /* U+1EB7 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */
- XK_Ebelowdot = 0x1001eb8, /* U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW */
- XK_ebelowdot = 0x1001eb9, /* U+1EB9 LATIN SMALL LETTER E WITH DOT BELOW */
- XK_Ehook = 0x1001eba, /* U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE */
- XK_ehook = 0x1001ebb, /* U+1EBB LATIN SMALL LETTER E WITH HOOK ABOVE */
- XK_Etilde = 0x1001ebc, /* U+1EBC LATIN CAPITAL LETTER E WITH TILDE */
- XK_etilde = 0x1001ebd, /* U+1EBD LATIN SMALL LETTER E WITH TILDE */
- XK_Ecircumflexacute = 0x1001ebe, /* U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */
- XK_ecircumflexacute = 0x1001ebf, /* U+1EBF LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */
- XK_Ecircumflexgrave = 0x1001ec0, /* U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */
- XK_ecircumflexgrave = 0x1001ec1, /* U+1EC1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */
- XK_Ecircumflexhook = 0x1001ec2, /* U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_ecircumflexhook = 0x1001ec3, /* U+1EC3 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_Ecircumflextilde = 0x1001ec4, /* U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */
- XK_ecircumflextilde = 0x1001ec5, /* U+1EC5 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */
- XK_Ecircumflexbelowdot = 0x1001ec6, /* U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
- XK_ecircumflexbelowdot = 0x1001ec7, /* U+1EC7 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
- XK_Ihook = 0x1001ec8, /* U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE */
- XK_ihook = 0x1001ec9, /* U+1EC9 LATIN SMALL LETTER I WITH HOOK ABOVE */
- XK_Ibelowdot = 0x1001eca, /* U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW */
- XK_ibelowdot = 0x1001ecb, /* U+1ECB LATIN SMALL LETTER I WITH DOT BELOW */
- XK_Obelowdot = 0x1001ecc, /* U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW */
- XK_obelowdot = 0x1001ecd, /* U+1ECD LATIN SMALL LETTER O WITH DOT BELOW */
- XK_Ohook = 0x1001ece, /* U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE */
- XK_ohook = 0x1001ecf, /* U+1ECF LATIN SMALL LETTER O WITH HOOK ABOVE */
- XK_Ocircumflexacute = 0x1001ed0, /* U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */
- XK_ocircumflexacute = 0x1001ed1, /* U+1ED1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */
- XK_Ocircumflexgrave = 0x1001ed2, /* U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */
- XK_ocircumflexgrave = 0x1001ed3, /* U+1ED3 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */
- XK_Ocircumflexhook = 0x1001ed4, /* U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_ocircumflexhook = 0x1001ed5, /* U+1ED5 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
- XK_Ocircumflextilde = 0x1001ed6, /* U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */
- XK_ocircumflextilde = 0x1001ed7, /* U+1ED7 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */
- XK_Ocircumflexbelowdot = 0x1001ed8, /* U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
- XK_ocircumflexbelowdot = 0x1001ed9, /* U+1ED9 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
- XK_Ohornacute = 0x1001eda, /* U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE */
- XK_ohornacute = 0x1001edb, /* U+1EDB LATIN SMALL LETTER O WITH HORN AND ACUTE */
- XK_Ohorngrave = 0x1001edc, /* U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE */
- XK_ohorngrave = 0x1001edd, /* U+1EDD LATIN SMALL LETTER O WITH HORN AND GRAVE */
- XK_Ohornhook = 0x1001ede, /* U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */
- XK_ohornhook = 0x1001edf, /* U+1EDF LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */
- XK_Ohorntilde = 0x1001ee0, /* U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE */
- XK_ohorntilde = 0x1001ee1, /* U+1EE1 LATIN SMALL LETTER O WITH HORN AND TILDE */
- XK_Ohornbelowdot = 0x1001ee2, /* U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */
- XK_ohornbelowdot = 0x1001ee3, /* U+1EE3 LATIN SMALL LETTER O WITH HORN AND DOT BELOW */
- XK_Ubelowdot = 0x1001ee4, /* U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW */
- XK_ubelowdot = 0x1001ee5, /* U+1EE5 LATIN SMALL LETTER U WITH DOT BELOW */
- XK_Uhook = 0x1001ee6, /* U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE */
- XK_uhook = 0x1001ee7, /* U+1EE7 LATIN SMALL LETTER U WITH HOOK ABOVE */
- XK_Uhornacute = 0x1001ee8, /* U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE */
- XK_uhornacute = 0x1001ee9, /* U+1EE9 LATIN SMALL LETTER U WITH HORN AND ACUTE */
- XK_Uhorngrave = 0x1001eea, /* U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE */
- XK_uhorngrave = 0x1001eeb, /* U+1EEB LATIN SMALL LETTER U WITH HORN AND GRAVE */
- XK_Uhornhook = 0x1001eec, /* U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */
- XK_uhornhook = 0x1001eed, /* U+1EED LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */
- XK_Uhorntilde = 0x1001eee, /* U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE */
- XK_uhorntilde = 0x1001eef, /* U+1EEF LATIN SMALL LETTER U WITH HORN AND TILDE */
- XK_Uhornbelowdot = 0x1001ef0, /* U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */
- XK_uhornbelowdot = 0x1001ef1, /* U+1EF1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW */
- XK_Ybelowdot = 0x1001ef4, /* U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW */
- XK_ybelowdot = 0x1001ef5, /* U+1EF5 LATIN SMALL LETTER Y WITH DOT BELOW */
- XK_Yhook = 0x1001ef6, /* U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE */
- XK_yhook = 0x1001ef7, /* U+1EF7 LATIN SMALL LETTER Y WITH HOOK ABOVE */
- XK_Ytilde = 0x1001ef8, /* U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE */
- XK_ytilde = 0x1001ef9, /* U+1EF9 LATIN SMALL LETTER Y WITH TILDE */
- XK_Ohorn = 0x10001a0, /* U+01A0 LATIN CAPITAL LETTER O WITH HORN */
- XK_ohorn = 0x10001a1, /* U+01A1 LATIN SMALL LETTER O WITH HORN */
- XK_Uhorn = 0x10001af, /* U+01AF LATIN CAPITAL LETTER U WITH HORN */
- XK_uhorn = 0x10001b0, /* U+01B0 LATIN SMALL LETTER U WITH HORN */
- XK_EcuSign = 0x10020a0, /* U+20A0 EURO-CURRENCY SIGN */
- XK_ColonSign = 0x10020a1, /* U+20A1 COLON SIGN */
- XK_CruzeiroSign = 0x10020a2, /* U+20A2 CRUZEIRO SIGN */
- XK_FFrancSign = 0x10020a3, /* U+20A3 FRENCH FRANC SIGN */
- XK_LiraSign = 0x10020a4, /* U+20A4 LIRA SIGN */
- XK_MillSign = 0x10020a5, /* U+20A5 MILL SIGN */
- XK_NairaSign = 0x10020a6, /* U+20A6 NAIRA SIGN */
- XK_PesetaSign = 0x10020a7, /* U+20A7 PESETA SIGN */
- XK_RupeeSign = 0x10020a8, /* U+20A8 RUPEE SIGN */
- XK_WonSign = 0x10020a9, /* U+20A9 WON SIGN */
- XK_NewSheqelSign = 0x10020aa, /* U+20AA NEW SHEQEL SIGN */
- XK_DongSign = 0x10020ab, /* U+20AB DONG SIGN */
- XK_EuroSign = 0x20ac, /* U+20AC EURO SIGN */
+ XK_BackSpace = 0xff08, /* Back space, back char */
+ XK_Tab = 0xff09,
+ XK_Linefeed = 0xff0a, /* Linefeed, LF */
+ XK_Clear = 0xff0b,
+ XK_Return = 0xff0d, /* Return, enter */
+ XK_Pause = 0xff13, /* Pause, hold */
+ XK_Scroll_Lock = 0xff14,
+ XK_Sys_Req = 0xff15,
+ XK_Escape = 0xff1b,
+ XK_Delete = 0xffff, /* Delete, rubout */
+ XK_Multi_key = 0xff20, /* Multi-key character compose */
+ XK_Codeinput = 0xff37,
+ XK_SingleCandidate = 0xff3c,
+ XK_MultipleCandidate = 0xff3d,
+ XK_PreviousCandidate = 0xff3e,
+ XK_Kanji = 0xff21, /* Kanji, Kanji convert */
+ XK_Muhenkan = 0xff22, /* Cancel Conversion */
+ XK_Henkan_Mode = 0xff23, /* Start/Stop Conversion */
+ XK_Henkan = 0xff23, /* Alias for Henkan_Mode */
+ XK_Romaji = 0xff24, /* to Romaji */
+ XK_Hiragana = 0xff25, /* to Hiragana */
+ XK_Katakana = 0xff26, /* to Katakana */
+ XK_Hiragana_Katakana = 0xff27, /* Hiragana/Katakana toggle */
+ XK_Zenkaku = 0xff28, /* to Zenkaku */
+ XK_Hankaku = 0xff29, /* to Hankaku */
+ XK_Zenkaku_Hankaku = 0xff2a, /* Zenkaku/Hankaku toggle */
+ XK_Touroku = 0xff2b, /* Add to Dictionary */
+ XK_Massyo = 0xff2c, /* Delete from Dictionary */
+ XK_Kana_Lock = 0xff2d, /* Kana Lock */
+ XK_Kana_Shift = 0xff2e, /* Kana Shift */
+ XK_Eisu_Shift = 0xff2f, /* Alphanumeric Shift */
+ XK_Eisu_toggle = 0xff30, /* Alphanumeric toggle */
+ XK_Kanji_Bangou = 0xff37, /* Codeinput */
+ XK_Zen_Koho = 0xff3d, /* Multiple/All Candidate(s) */
+ XK_Mae_Koho = 0xff3e, /* Previous Candidate */
+ XK_Home = 0xff50,
+ XK_Left = 0xff51, /* Move left, left arrow */
+ XK_Up = 0xff52, /* Move up, up arrow */
+ XK_Right = 0xff53, /* Move right, right arrow */
+ XK_Down = 0xff54, /* Move down, down arrow */
+ XK_Prior = 0xff55, /* Prior, previous */
+ XK_Page_Up = 0xff55,
+ XK_Next = 0xff56, /* Next */
+ XK_Page_Down = 0xff56,
+ XK_End = 0xff57, /* EOL */
+ XK_Begin = 0xff58, /* BOL */
+ XK_Select = 0xff60, /* Select, mark */
+ XK_Print = 0xff61,
+ XK_Execute = 0xff62, /* Execute, run, do */
+ XK_Insert = 0xff63, /* Insert, insert here */
+ XK_Undo = 0xff65,
+ XK_Redo = 0xff66, /* Redo, again */
+ XK_Menu = 0xff67,
+ XK_Find = 0xff68, /* Find, search */
+ XK_Cancel = 0xff69, /* Cancel, stop, abort, exit */
+ XK_Help = 0xff6a, /* Help */
+ XK_Break = 0xff6b,
+ XK_Mode_switch = 0xff7e, /* Character set switch */
+ XK_script_switch = 0xff7e, /* Alias for mode_switch */
+ XK_Num_Lock = 0xff7f,
+ XK_KP_Space = 0xff80, /* Space */
+ XK_KP_Tab = 0xff89,
+ XK_KP_Enter = 0xff8d, /* Enter */
+ XK_KP_F1 = 0xff91, /* PF1, KP_A, ... */
+ XK_KP_F2 = 0xff92,
+ XK_KP_F3 = 0xff93,
+ XK_KP_F4 = 0xff94,
+ XK_KP_Home = 0xff95,
+ XK_KP_Left = 0xff96,
+ XK_KP_Up = 0xff97,
+ XK_KP_Right = 0xff98,
+ XK_KP_Down = 0xff99,
+ XK_KP_Prior = 0xff9a,
+ XK_KP_Page_Up = 0xff9a,
+ XK_KP_Next = 0xff9b,
+ XK_KP_Page_Down = 0xff9b,
+ XK_KP_End = 0xff9c,
+ XK_KP_Begin = 0xff9d,
+ XK_KP_Insert = 0xff9e,
+ XK_KP_Delete = 0xff9f,
+ XK_KP_Equal = 0xffbd, /* Equals */
+ XK_KP_Multiply = 0xffaa,
+ XK_KP_Add = 0xffab,
+ XK_KP_Separator = 0xffac, /* Separator, often comma */
+ XK_KP_Subtract = 0xffad,
+ XK_KP_Decimal = 0xffae,
+ XK_KP_Divide = 0xffaf,
+ XK_KP_0 = 0xffb0,
+ XK_KP_1 = 0xffb1,
+ XK_KP_2 = 0xffb2,
+ XK_KP_3 = 0xffb3,
+ XK_KP_4 = 0xffb4,
+ XK_KP_5 = 0xffb5,
+ XK_KP_6 = 0xffb6,
+ XK_KP_7 = 0xffb7,
+ XK_KP_8 = 0xffb8,
+ XK_KP_9 = 0xffb9,
+ XK_F1 = 0xffbe,
+ XK_F2 = 0xffbf,
+ XK_F3 = 0xffc0,
+ XK_F4 = 0xffc1,
+ XK_F5 = 0xffc2,
+ XK_F6 = 0xffc3,
+ XK_F7 = 0xffc4,
+ XK_F8 = 0xffc5,
+ XK_F9 = 0xffc6,
+ XK_F10 = 0xffc7,
+ XK_F11 = 0xffc8,
+ XK_L1 = 0xffc8,
+ XK_F12 = 0xffc9,
+ XK_L2 = 0xffc9,
+ XK_F13 = 0xffca,
+ XK_L3 = 0xffca,
+ XK_F14 = 0xffcb,
+ XK_L4 = 0xffcb,
+ XK_F15 = 0xffcc,
+ XK_L5 = 0xffcc,
+ XK_F16 = 0xffcd,
+ XK_L6 = 0xffcd,
+ XK_F17 = 0xffce,
+ XK_L7 = 0xffce,
+ XK_F18 = 0xffcf,
+ XK_L8 = 0xffcf,
+ XK_F19 = 0xffd0,
+ XK_L9 = 0xffd0,
+ XK_F20 = 0xffd1,
+ XK_L10 = 0xffd1,
+ XK_F21 = 0xffd2,
+ XK_R1 = 0xffd2,
+ XK_F22 = 0xffd3,
+ XK_R2 = 0xffd3,
+ XK_F23 = 0xffd4,
+ XK_R3 = 0xffd4,
+ XK_F24 = 0xffd5,
+ XK_R4 = 0xffd5,
+ XK_F25 = 0xffd6,
+ XK_R5 = 0xffd6,
+ XK_F26 = 0xffd7,
+ XK_R6 = 0xffd7,
+ XK_F27 = 0xffd8,
+ XK_R7 = 0xffd8,
+ XK_F28 = 0xffd9,
+ XK_R8 = 0xffd9,
+ XK_F29 = 0xffda,
+ XK_R9 = 0xffda,
+ XK_F30 = 0xffdb,
+ XK_R10 = 0xffdb,
+ XK_F31 = 0xffdc,
+ XK_R11 = 0xffdc,
+ XK_F32 = 0xffdd,
+ XK_R12 = 0xffdd,
+ XK_F33 = 0xffde,
+ XK_R13 = 0xffde,
+ XK_F34 = 0xffdf,
+ XK_R14 = 0xffdf,
+ XK_F35 = 0xffe0,
+ XK_R15 = 0xffe0,
+ XK_Shift_L = 0xffe1, /* Left shift */
+ XK_Shift_R = 0xffe2, /* Right shift */
+ XK_Control_L = 0xffe3, /* Left control */
+ XK_Control_R = 0xffe4, /* Right control */
+ XK_Caps_Lock = 0xffe5, /* Caps lock */
+ XK_Shift_Lock = 0xffe6, /* Shift lock */
+ XK_Meta_L = 0xffe7, /* Left meta */
+ XK_Meta_R = 0xffe8, /* Right meta */
+ XK_Alt_L = 0xffe9, /* Left alt */
+ XK_Alt_R = 0xffea, /* Right alt */
+ XK_Super_L = 0xffeb, /* Left super */
+ XK_Super_R = 0xffec, /* Right super */
+ XK_Hyper_L = 0xffed, /* Left hyper */
+ XK_Hyper_R = 0xffee, /* Right hyper */
+ XK_ISO_Lock = 0xfe01,
+ XK_ISO_Level2_Latch = 0xfe02,
+ XK_ISO_Level3_Shift = 0xfe03,
+ XK_ISO_Level3_Latch = 0xfe04,
+ XK_ISO_Level3_Lock = 0xfe05,
+ XK_ISO_Group_Shift = 0xff7e, /* Alias for mode_switch */
+ XK_ISO_Group_Latch = 0xfe06,
+ XK_ISO_Group_Lock = 0xfe07,
+ XK_ISO_Next_Group = 0xfe08,
+ XK_ISO_Next_Group_Lock = 0xfe09,
+ XK_ISO_Prev_Group = 0xfe0a,
+ XK_ISO_Prev_Group_Lock = 0xfe0b,
+ XK_ISO_First_Group = 0xfe0c,
+ XK_ISO_First_Group_Lock = 0xfe0d,
+ XK_ISO_Last_Group = 0xfe0e,
+ XK_ISO_Last_Group_Lock = 0xfe0f,
+ XK_ISO_Left_Tab = 0xfe20,
+ XK_ISO_Move_Line_Up = 0xfe21,
+ XK_ISO_Move_Line_Down = 0xfe22,
+ XK_ISO_Partial_Line_Up = 0xfe23,
+ XK_ISO_Partial_Line_Down = 0xfe24,
+ XK_ISO_Partial_Space_Left = 0xfe25,
+ XK_ISO_Partial_Space_Right = 0xfe26,
+ XK_ISO_Set_Margin_Left = 0xfe27,
+ XK_ISO_Set_Margin_Right = 0xfe28,
+ XK_ISO_Release_Margin_Left = 0xfe29,
+ XK_ISO_Release_Margin_Right = 0xfe2a,
+ XK_ISO_Release_Both_Margins = 0xfe2b,
+ XK_ISO_Fast_Cursor_Left = 0xfe2c,
+ XK_ISO_Fast_Cursor_Right = 0xfe2d,
+ XK_ISO_Fast_Cursor_Up = 0xfe2e,
+ XK_ISO_Fast_Cursor_Down = 0xfe2f,
+ XK_ISO_Continuous_Underline = 0xfe30,
+ XK_ISO_Discontinuous_Underline = 0xfe31,
+ XK_ISO_Emphasize = 0xfe32,
+ XK_ISO_Center_Object = 0xfe33,
+ XK_ISO_Enter = 0xfe34,
+ XK_dead_grave = 0xfe50,
+ XK_dead_acute = 0xfe51,
+ XK_dead_circumflex = 0xfe52,
+ XK_dead_tilde = 0xfe53,
+ XK_dead_macron = 0xfe54,
+ XK_dead_breve = 0xfe55,
+ XK_dead_abovedot = 0xfe56,
+ XK_dead_diaeresis = 0xfe57,
+ XK_dead_abovering = 0xfe58,
+ XK_dead_doubleacute = 0xfe59,
+ XK_dead_caron = 0xfe5a,
+ XK_dead_cedilla = 0xfe5b,
+ XK_dead_ogonek = 0xfe5c,
+ XK_dead_iota = 0xfe5d,
+ XK_dead_voiced_sound = 0xfe5e,
+ XK_dead_semivoiced_sound = 0xfe5f,
+ XK_dead_belowdot = 0xfe60,
+ XK_dead_hook = 0xfe61,
+ XK_dead_horn = 0xfe62,
+ XK_First_Virtual_Screen = 0xfed0,
+ XK_Prev_Virtual_Screen = 0xfed1,
+ XK_Next_Virtual_Screen = 0xfed2,
+ XK_Last_Virtual_Screen = 0xfed4,
+ XK_Terminate_Server = 0xfed5,
+ XK_AccessX_Enable = 0xfe70,
+ XK_AccessX_Feedback_Enable = 0xfe71,
+ XK_RepeatKeys_Enable = 0xfe72,
+ XK_SlowKeys_Enable = 0xfe73,
+ XK_BounceKeys_Enable = 0xfe74,
+ XK_StickyKeys_Enable = 0xfe75,
+ XK_MouseKeys_Enable = 0xfe76,
+ XK_MouseKeys_Accel_Enable = 0xfe77,
+ XK_Overlay1_Enable = 0xfe78,
+ XK_Overlay2_Enable = 0xfe79,
+ XK_AudibleBell_Enable = 0xfe7a,
+ XK_Pointer_Left = 0xfee0,
+ XK_Pointer_Right = 0xfee1,
+ XK_Pointer_Up = 0xfee2,
+ XK_Pointer_Down = 0xfee3,
+ XK_Pointer_UpLeft = 0xfee4,
+ XK_Pointer_UpRight = 0xfee5,
+ XK_Pointer_DownLeft = 0xfee6,
+ XK_Pointer_DownRight = 0xfee7,
+ XK_Pointer_Button_Dflt = 0xfee8,
+ XK_Pointer_Button1 = 0xfee9,
+ XK_Pointer_Button2 = 0xfeea,
+ XK_Pointer_Button3 = 0xfeeb,
+ XK_Pointer_Button4 = 0xfeec,
+ XK_Pointer_Button5 = 0xfeed,
+ XK_Pointer_DblClick_Dflt = 0xfeee,
+ XK_Pointer_DblClick1 = 0xfeef,
+ XK_Pointer_DblClick2 = 0xfef0,
+ XK_Pointer_DblClick3 = 0xfef1,
+ XK_Pointer_DblClick4 = 0xfef2,
+ XK_Pointer_DblClick5 = 0xfef3,
+ XK_Pointer_Drag_Dflt = 0xfef4,
+ XK_Pointer_Drag1 = 0xfef5,
+ XK_Pointer_Drag2 = 0xfef6,
+ XK_Pointer_Drag3 = 0xfef7,
+ XK_Pointer_Drag4 = 0xfef8,
+ XK_Pointer_Drag5 = 0xfefd,
+ XK_Pointer_EnableKeys = 0xfef9,
+ XK_Pointer_Accelerate = 0xfefa,
+ XK_Pointer_DfltBtnNext = 0xfefb,
+ XK_Pointer_DfltBtnPrev = 0xfefc,
+ XK_3270_Duplicate = 0xfd01,
+ XK_3270_FieldMark = 0xfd02,
+ XK_3270_Right2 = 0xfd03,
+ XK_3270_Left2 = 0xfd04,
+ XK_3270_BackTab = 0xfd05,
+ XK_3270_EraseEOF = 0xfd06,
+ XK_3270_EraseInput = 0xfd07,
+ XK_3270_Reset = 0xfd08,
+ XK_3270_Quit = 0xfd09,
+ XK_3270_PA1 = 0xfd0a,
+ XK_3270_PA2 = 0xfd0b,
+ XK_3270_PA3 = 0xfd0c,
+ XK_3270_Test = 0xfd0d,
+ XK_3270_Attn = 0xfd0e,
+ XK_3270_CursorBlink = 0xfd0f,
+ XK_3270_AltCursor = 0xfd10,
+ XK_3270_KeyClick = 0xfd11,
+ XK_3270_Jump = 0xfd12,
+ XK_3270_Ident = 0xfd13,
+ XK_3270_Rule = 0xfd14,
+ XK_3270_Copy = 0xfd15,
+ XK_3270_Play = 0xfd16,
+ XK_3270_Setup = 0xfd17,
+ XK_3270_Record = 0xfd18,
+ XK_3270_ChangeScreen = 0xfd19,
+ XK_3270_DeleteWord = 0xfd1a,
+ XK_3270_ExSelect = 0xfd1b,
+ XK_3270_CursorSelect = 0xfd1c,
+ XK_3270_PrintScreen = 0xfd1d,
+ XK_3270_Enter = 0xfd1e,
+ XK_space = 0x0020, /* U+0020 SPACE */
+ XK_exclam = 0x0021, /* U+0021 EXCLAMATION MARK */
+ XK_quotedbl = 0x0022, /* U+0022 QUOTATION MARK */
+ XK_numbersign = 0x0023, /* U+0023 NUMBER SIGN */
+ XK_dollar = 0x0024, /* U+0024 DOLLAR SIGN */
+ XK_percent = 0x0025, /* U+0025 PERCENT SIGN */
+ XK_ampersand = 0x0026, /* U+0026 AMPERSAND */
+ XK_apostrophe = 0x0027, /* U+0027 APOSTROPHE */
+ XK_quoteright = 0x0027, /* deprecated */
+ XK_parenleft = 0x0028, /* U+0028 LEFT PARENTHESIS */
+ XK_parenright = 0x0029, /* U+0029 RIGHT PARENTHESIS */
+ XK_asterisk = 0x002a, /* U+002A ASTERISK */
+ XK_plus = 0x002b, /* U+002B PLUS SIGN */
+ XK_comma = 0x002c, /* U+002C COMMA */
+ XK_minus = 0x002d, /* U+002D HYPHEN-MINUS */
+ XK_period = 0x002e, /* U+002E FULL STOP */
+ XK_slash = 0x002f, /* U+002F SOLIDUS */
+ XK_0 = 0x0030, /* U+0030 DIGIT ZERO */
+ XK_1 = 0x0031, /* U+0031 DIGIT ONE */
+ XK_2 = 0x0032, /* U+0032 DIGIT TWO */
+ XK_3 = 0x0033, /* U+0033 DIGIT THREE */
+ XK_4 = 0x0034, /* U+0034 DIGIT FOUR */
+ XK_5 = 0x0035, /* U+0035 DIGIT FIVE */
+ XK_6 = 0x0036, /* U+0036 DIGIT SIX */
+ XK_7 = 0x0037, /* U+0037 DIGIT SEVEN */
+ XK_8 = 0x0038, /* U+0038 DIGIT EIGHT */
+ XK_9 = 0x0039, /* U+0039 DIGIT NINE */
+ XK_colon = 0x003a, /* U+003A COLON */
+ XK_semicolon = 0x003b, /* U+003B SEMICOLON */
+ XK_less = 0x003c, /* U+003C LESS-THAN SIGN */
+ XK_equal = 0x003d, /* U+003D EQUALS SIGN */
+ XK_greater = 0x003e, /* U+003E GREATER-THAN SIGN */
+ XK_question = 0x003f, /* U+003F QUESTION MARK */
+ XK_at = 0x0040, /* U+0040 COMMERCIAL AT */
+ XK_A = 0x0041, /* U+0041 LATIN CAPITAL LETTER A */
+ XK_B = 0x0042, /* U+0042 LATIN CAPITAL LETTER B */
+ XK_C = 0x0043, /* U+0043 LATIN CAPITAL LETTER C */
+ XK_D = 0x0044, /* U+0044 LATIN CAPITAL LETTER D */
+ XK_E = 0x0045, /* U+0045 LATIN CAPITAL LETTER E */
+ XK_F = 0x0046, /* U+0046 LATIN CAPITAL LETTER F */
+ XK_G = 0x0047, /* U+0047 LATIN CAPITAL LETTER G */
+ XK_H = 0x0048, /* U+0048 LATIN CAPITAL LETTER H */
+ XK_I = 0x0049, /* U+0049 LATIN CAPITAL LETTER I */
+ XK_J = 0x004a, /* U+004A LATIN CAPITAL LETTER J */
+ XK_K = 0x004b, /* U+004B LATIN CAPITAL LETTER K */
+ XK_L = 0x004c, /* U+004C LATIN CAPITAL LETTER L */
+ XK_M = 0x004d, /* U+004D LATIN CAPITAL LETTER M */
+ XK_N = 0x004e, /* U+004E LATIN CAPITAL LETTER N */
+ XK_O = 0x004f, /* U+004F LATIN CAPITAL LETTER O */
+ XK_P = 0x0050, /* U+0050 LATIN CAPITAL LETTER P */
+ XK_Q = 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */
+ XK_R = 0x0052, /* U+0052 LATIN CAPITAL LETTER R */
+ XK_S = 0x0053, /* U+0053 LATIN CAPITAL LETTER S */
+ XK_T = 0x0054, /* U+0054 LATIN CAPITAL LETTER T */
+ XK_U = 0x0055, /* U+0055 LATIN CAPITAL LETTER U */
+ XK_V = 0x0056, /* U+0056 LATIN CAPITAL LETTER V */
+ XK_W = 0x0057, /* U+0057 LATIN CAPITAL LETTER W */
+ XK_X = 0x0058, /* U+0058 LATIN CAPITAL LETTER X */
+ XK_Y = 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */
+ XK_Z = 0x005a, /* U+005A LATIN CAPITAL LETTER Z */
+ XK_bracketleft = 0x005b, /* U+005B LEFT SQUARE BRACKET */
+ XK_backslash = 0x005c, /* U+005C REVERSE SOLIDUS */
+ XK_bracketright = 0x005d, /* U+005D RIGHT SQUARE BRACKET */
+ XK_asciicircum = 0x005e, /* U+005E CIRCUMFLEX ACCENT */
+ XK_underscore = 0x005f, /* U+005F LOW LINE */
+ XK_grave = 0x0060, /* U+0060 GRAVE ACCENT */
+ XK_quoteleft = 0x0060, /* deprecated */
+ XK_a = 0x0061, /* U+0061 LATIN SMALL LETTER A */
+ XK_b = 0x0062, /* U+0062 LATIN SMALL LETTER B */
+ XK_c = 0x0063, /* U+0063 LATIN SMALL LETTER C */
+ XK_d = 0x0064, /* U+0064 LATIN SMALL LETTER D */
+ XK_e = 0x0065, /* U+0065 LATIN SMALL LETTER E */
+ XK_f = 0x0066, /* U+0066 LATIN SMALL LETTER F */
+ XK_g = 0x0067, /* U+0067 LATIN SMALL LETTER G */
+ XK_h = 0x0068, /* U+0068 LATIN SMALL LETTER H */
+ XK_i = 0x0069, /* U+0069 LATIN SMALL LETTER I */
+ XK_j = 0x006a, /* U+006A LATIN SMALL LETTER J */
+ XK_k = 0x006b, /* U+006B LATIN SMALL LETTER K */
+ XK_l = 0x006c, /* U+006C LATIN SMALL LETTER L */
+ XK_m = 0x006d, /* U+006D LATIN SMALL LETTER M */
+ XK_n = 0x006e, /* U+006E LATIN SMALL LETTER N */
+ XK_o = 0x006f, /* U+006F LATIN SMALL LETTER O */
+ XK_p = 0x0070, /* U+0070 LATIN SMALL LETTER P */
+ XK_q = 0x0071, /* U+0071 LATIN SMALL LETTER Q */
+ XK_r = 0x0072, /* U+0072 LATIN SMALL LETTER R */
+ XK_s = 0x0073, /* U+0073 LATIN SMALL LETTER S */
+ XK_t = 0x0074, /* U+0074 LATIN SMALL LETTER T */
+ XK_u = 0x0075, /* U+0075 LATIN SMALL LETTER U */
+ XK_v = 0x0076, /* U+0076 LATIN SMALL LETTER V */
+ XK_w = 0x0077, /* U+0077 LATIN SMALL LETTER W */
+ XK_x = 0x0078, /* U+0078 LATIN SMALL LETTER X */
+ XK_y = 0x0079, /* U+0079 LATIN SMALL LETTER Y */
+ XK_z = 0x007a, /* U+007A LATIN SMALL LETTER Z */
+ XK_braceleft = 0x007b, /* U+007B LEFT CURLY BRACKET */
+ XK_bar = 0x007c, /* U+007C VERTICAL LINE */
+ XK_braceright = 0x007d, /* U+007D RIGHT CURLY BRACKET */
+ XK_asciitilde = 0x007e, /* U+007E TILDE */
+ XK_nobreakspace = 0x00a0, /* U+00A0 NO-BREAK SPACE */
+ XK_exclamdown = 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */
+ XK_cent = 0x00a2, /* U+00A2 CENT SIGN */
+ XK_sterling = 0x00a3, /* U+00A3 POUND SIGN */
+ XK_currency = 0x00a4, /* U+00A4 CURRENCY SIGN */
+ XK_yen = 0x00a5, /* U+00A5 YEN SIGN */
+ XK_brokenbar = 0x00a6, /* U+00A6 BROKEN BAR */
+ XK_section = 0x00a7, /* U+00A7 SECTION SIGN */
+ XK_diaeresis = 0x00a8, /* U+00A8 DIAERESIS */
+ XK_copyright = 0x00a9, /* U+00A9 COPYRIGHT SIGN */
+ XK_ordfeminine = 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */
+ XK_guillemotleft = 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ XK_notsign = 0x00ac, /* U+00AC NOT SIGN */
+ XK_hyphen = 0x00ad, /* U+00AD SOFT HYPHEN */
+ XK_registered = 0x00ae, /* U+00AE REGISTERED SIGN */
+ XK_macron = 0x00af, /* U+00AF MACRON */
+ XK_degree = 0x00b0, /* U+00B0 DEGREE SIGN */
+ XK_plusminus = 0x00b1, /* U+00B1 PLUS-MINUS SIGN */
+ XK_twosuperior = 0x00b2, /* U+00B2 SUPERSCRIPT TWO */
+ XK_threesuperior = 0x00b3, /* U+00B3 SUPERSCRIPT THREE */
+ XK_acute = 0x00b4, /* U+00B4 ACUTE ACCENT */
+ XK_mu = 0x00b5, /* U+00B5 MICRO SIGN */
+ XK_paragraph = 0x00b6, /* U+00B6 PILCROW SIGN */
+ XK_periodcentered = 0x00b7, /* U+00B7 MIDDLE DOT */
+ XK_cedilla = 0x00b8, /* U+00B8 CEDILLA */
+ XK_onesuperior = 0x00b9, /* U+00B9 SUPERSCRIPT ONE */
+ XK_masculine = 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */
+ XK_guillemotright = 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ XK_onequarter = 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */
+ XK_onehalf = 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */
+ XK_threequarters = 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */
+ XK_questiondown = 0x00bf, /* U+00BF INVERTED QUESTION MARK */
+ XK_Agrave = 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */
+ XK_Aacute = 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */
+ XK_Acircumflex = 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ XK_Atilde = 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */
+ XK_Adiaeresis = 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */
+ XK_Aring = 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */
+ XK_AE = 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */
+ XK_Ccedilla = 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */
+ XK_Egrave = 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */
+ XK_Eacute = 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */
+ XK_Ecircumflex = 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ XK_Ediaeresis = 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */
+ XK_Igrave = 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */
+ XK_Iacute = 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */
+ XK_Icircumflex = 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ XK_Idiaeresis = 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */
+ XK_ETH = 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */
+ XK_Eth = 0x00d0, /* deprecated */
+ XK_Ntilde = 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */
+ XK_Ograve = 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */
+ XK_Oacute = 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */
+ XK_Ocircumflex = 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ XK_Otilde = 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */
+ XK_Odiaeresis = 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */
+ XK_multiply = 0x00d7, /* U+00D7 MULTIPLICATION SIGN */
+ XK_Oslash = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
+ XK_Ooblique = 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */
+ XK_Ugrave = 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */
+ XK_Uacute = 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */
+ XK_Ucircumflex = 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ XK_Udiaeresis = 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */
+ XK_Yacute = 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */
+ XK_THORN = 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */
+ XK_Thorn = 0x00de, /* deprecated */
+ XK_ssharp = 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */
+ XK_agrave = 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */
+ XK_aacute = 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */
+ XK_acircumflex = 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ XK_atilde = 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */
+ XK_adiaeresis = 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */
+ XK_aring = 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */
+ XK_ae = 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */
+ XK_ccedilla = 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */
+ XK_egrave = 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */
+ XK_eacute = 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */
+ XK_ecircumflex = 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ XK_ediaeresis = 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */
+ XK_igrave = 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */
+ XK_iacute = 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */
+ XK_icircumflex = 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ XK_idiaeresis = 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */
+ XK_eth = 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */
+ XK_ntilde = 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */
+ XK_ograve = 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */
+ XK_oacute = 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */
+ XK_ocircumflex = 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ XK_otilde = 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */
+ XK_odiaeresis = 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */
+ XK_division = 0x00f7, /* U+00F7 DIVISION SIGN */
+ XK_oslash = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
+ XK_ooblique = 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */
+ XK_ugrave = 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */
+ XK_uacute = 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */
+ XK_ucircumflex = 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */
+ XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
+ XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */
+ XK_ydiaeresis = 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
+ XK_Aogonek = 0x01a1, /* U+0104 LATIN CAPITAL LETTER A WITH OGONEK */
+ XK_breve = 0x01a2, /* U+02D8 BREVE */
+ XK_Lstroke = 0x01a3, /* U+0141 LATIN CAPITAL LETTER L WITH STROKE */
+ XK_Lcaron = 0x01a5, /* U+013D LATIN CAPITAL LETTER L WITH CARON */
+ XK_Sacute = 0x01a6, /* U+015A LATIN CAPITAL LETTER S WITH ACUTE */
+ XK_Scaron = 0x01a9, /* U+0160 LATIN CAPITAL LETTER S WITH CARON */
+ XK_Scedilla = 0x01aa, /* U+015E LATIN CAPITAL LETTER S WITH CEDILLA */
+ XK_Tcaron = 0x01ab, /* U+0164 LATIN CAPITAL LETTER T WITH CARON */
+ XK_Zacute = 0x01ac, /* U+0179 LATIN CAPITAL LETTER Z WITH ACUTE */
+ XK_Zcaron = 0x01ae, /* U+017D LATIN CAPITAL LETTER Z WITH CARON */
+ XK_Zabovedot = 0x01af, /* U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+ XK_aogonek = 0x01b1, /* U+0105 LATIN SMALL LETTER A WITH OGONEK */
+ XK_ogonek = 0x01b2, /* U+02DB OGONEK */
+ XK_lstroke = 0x01b3, /* U+0142 LATIN SMALL LETTER L WITH STROKE */
+ XK_lcaron = 0x01b5, /* U+013E LATIN SMALL LETTER L WITH CARON */
+ XK_sacute = 0x01b6, /* U+015B LATIN SMALL LETTER S WITH ACUTE */
+ XK_caron = 0x01b7, /* U+02C7 CARON */
+ XK_scaron = 0x01b9, /* U+0161 LATIN SMALL LETTER S WITH CARON */
+ XK_scedilla = 0x01ba, /* U+015F LATIN SMALL LETTER S WITH CEDILLA */
+ XK_tcaron = 0x01bb, /* U+0165 LATIN SMALL LETTER T WITH CARON */
+ XK_zacute = 0x01bc, /* U+017A LATIN SMALL LETTER Z WITH ACUTE */
+ XK_doubleacute = 0x01bd, /* U+02DD DOUBLE ACUTE ACCENT */
+ XK_zcaron = 0x01be, /* U+017E LATIN SMALL LETTER Z WITH CARON */
+ XK_zabovedot = 0x01bf, /* U+017C LATIN SMALL LETTER Z WITH DOT ABOVE */
+ XK_Racute = 0x01c0, /* U+0154 LATIN CAPITAL LETTER R WITH ACUTE */
+ XK_Abreve = 0x01c3, /* U+0102 LATIN CAPITAL LETTER A WITH BREVE */
+ XK_Lacute = 0x01c5, /* U+0139 LATIN CAPITAL LETTER L WITH ACUTE */
+ XK_Cacute = 0x01c6, /* U+0106 LATIN CAPITAL LETTER C WITH ACUTE */
+ XK_Ccaron = 0x01c8, /* U+010C LATIN CAPITAL LETTER C WITH CARON */
+ XK_Eogonek = 0x01ca, /* U+0118 LATIN CAPITAL LETTER E WITH OGONEK */
+ XK_Ecaron = 0x01cc, /* U+011A LATIN CAPITAL LETTER E WITH CARON */
+ XK_Dcaron = 0x01cf, /* U+010E LATIN CAPITAL LETTER D WITH CARON */
+ XK_Dstroke = 0x01d0, /* U+0110 LATIN CAPITAL LETTER D WITH STROKE */
+ XK_Nacute = 0x01d1, /* U+0143 LATIN CAPITAL LETTER N WITH ACUTE */
+ XK_Ncaron = 0x01d2, /* U+0147 LATIN CAPITAL LETTER N WITH CARON */
+ XK_Odoubleacute = 0x01d5, /* U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+ XK_Rcaron = 0x01d8, /* U+0158 LATIN CAPITAL LETTER R WITH CARON */
+ XK_Uring = 0x01d9, /* U+016E LATIN CAPITAL LETTER U WITH RING ABOVE */
+ XK_Udoubleacute = 0x01db, /* U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+ XK_Tcedilla = 0x01de, /* U+0162 LATIN CAPITAL LETTER T WITH CEDILLA */
+ XK_racute = 0x01e0, /* U+0155 LATIN SMALL LETTER R WITH ACUTE */
+ XK_abreve = 0x01e3, /* U+0103 LATIN SMALL LETTER A WITH BREVE */
+ XK_lacute = 0x01e5, /* U+013A LATIN SMALL LETTER L WITH ACUTE */
+ XK_cacute = 0x01e6, /* U+0107 LATIN SMALL LETTER C WITH ACUTE */
+ XK_ccaron = 0x01e8, /* U+010D LATIN SMALL LETTER C WITH CARON */
+ XK_eogonek = 0x01ea, /* U+0119 LATIN SMALL LETTER E WITH OGONEK */
+ XK_ecaron = 0x01ec, /* U+011B LATIN SMALL LETTER E WITH CARON */
+ XK_dcaron = 0x01ef, /* U+010F LATIN SMALL LETTER D WITH CARON */
+ XK_dstroke = 0x01f0, /* U+0111 LATIN SMALL LETTER D WITH STROKE */
+ XK_nacute = 0x01f1, /* U+0144 LATIN SMALL LETTER N WITH ACUTE */
+ XK_ncaron = 0x01f2, /* U+0148 LATIN SMALL LETTER N WITH CARON */
+ XK_odoubleacute = 0x01f5, /* U+0151 LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+ XK_udoubleacute = 0x01fb, /* U+0171 LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+ XK_rcaron = 0x01f8, /* U+0159 LATIN SMALL LETTER R WITH CARON */
+ XK_uring = 0x01f9, /* U+016F LATIN SMALL LETTER U WITH RING ABOVE */
+ XK_tcedilla = 0x01fe, /* U+0163 LATIN SMALL LETTER T WITH CEDILLA */
+ XK_abovedot = 0x01ff, /* U+02D9 DOT ABOVE */
+ XK_Hstroke = 0x02a1, /* U+0126 LATIN CAPITAL LETTER H WITH STROKE */
+ XK_Hcircumflex = 0x02a6, /* U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+ XK_Iabovedot = 0x02a9, /* U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ XK_Gbreve = 0x02ab, /* U+011E LATIN CAPITAL LETTER G WITH BREVE */
+ XK_Jcircumflex = 0x02ac, /* U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+ XK_hstroke = 0x02b1, /* U+0127 LATIN SMALL LETTER H WITH STROKE */
+ XK_hcircumflex = 0x02b6, /* U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX */
+ XK_idotless = 0x02b9, /* U+0131 LATIN SMALL LETTER DOTLESS I */
+ XK_gbreve = 0x02bb, /* U+011F LATIN SMALL LETTER G WITH BREVE */
+ XK_jcircumflex = 0x02bc, /* U+0135 LATIN SMALL LETTER J WITH CIRCUMFLEX */
+ XK_Cabovedot = 0x02c5, /* U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE */
+ XK_Ccircumflex = 0x02c6, /* U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+ XK_Gabovedot = 0x02d5, /* U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE */
+ XK_Gcircumflex = 0x02d8, /* U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+ XK_Ubreve = 0x02dd, /* U+016C LATIN CAPITAL LETTER U WITH BREVE */
+ XK_Scircumflex = 0x02de, /* U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+ XK_cabovedot = 0x02e5, /* U+010B LATIN SMALL LETTER C WITH DOT ABOVE */
+ XK_ccircumflex = 0x02e6, /* U+0109 LATIN SMALL LETTER C WITH CIRCUMFLEX */
+ XK_gabovedot = 0x02f5, /* U+0121 LATIN SMALL LETTER G WITH DOT ABOVE */
+ XK_gcircumflex = 0x02f8, /* U+011D LATIN SMALL LETTER G WITH CIRCUMFLEX */
+ XK_ubreve = 0x02fd, /* U+016D LATIN SMALL LETTER U WITH BREVE */
+ XK_scircumflex = 0x02fe, /* U+015D LATIN SMALL LETTER S WITH CIRCUMFLEX */
+ XK_kra = 0x03a2, /* U+0138 LATIN SMALL LETTER KRA */
+ XK_kappa = 0x03a2, /* deprecated */
+ XK_Rcedilla = 0x03a3, /* U+0156 LATIN CAPITAL LETTER R WITH CEDILLA */
+ XK_Itilde = 0x03a5, /* U+0128 LATIN CAPITAL LETTER I WITH TILDE */
+ XK_Lcedilla = 0x03a6, /* U+013B LATIN CAPITAL LETTER L WITH CEDILLA */
+ XK_Emacron = 0x03aa, /* U+0112 LATIN CAPITAL LETTER E WITH MACRON */
+ XK_Gcedilla = 0x03ab, /* U+0122 LATIN CAPITAL LETTER G WITH CEDILLA */
+ XK_Tslash = 0x03ac, /* U+0166 LATIN CAPITAL LETTER T WITH STROKE */
+ XK_rcedilla = 0x03b3, /* U+0157 LATIN SMALL LETTER R WITH CEDILLA */
+ XK_itilde = 0x03b5, /* U+0129 LATIN SMALL LETTER I WITH TILDE */
+ XK_lcedilla = 0x03b6, /* U+013C LATIN SMALL LETTER L WITH CEDILLA */
+ XK_emacron = 0x03ba, /* U+0113 LATIN SMALL LETTER E WITH MACRON */
+ XK_gcedilla = 0x03bb, /* U+0123 LATIN SMALL LETTER G WITH CEDILLA */
+ XK_tslash = 0x03bc, /* U+0167 LATIN SMALL LETTER T WITH STROKE */
+ XK_ENG = 0x03bd, /* U+014A LATIN CAPITAL LETTER ENG */
+ XK_eng = 0x03bf, /* U+014B LATIN SMALL LETTER ENG */
+ XK_Amacron = 0x03c0, /* U+0100 LATIN CAPITAL LETTER A WITH MACRON */
+ XK_Iogonek = 0x03c7, /* U+012E LATIN CAPITAL LETTER I WITH OGONEK */
+ XK_Eabovedot = 0x03cc, /* U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE */
+ XK_Imacron = 0x03cf, /* U+012A LATIN CAPITAL LETTER I WITH MACRON */
+ XK_Ncedilla = 0x03d1, /* U+0145 LATIN CAPITAL LETTER N WITH CEDILLA */
+ XK_Omacron = 0x03d2, /* U+014C LATIN CAPITAL LETTER O WITH MACRON */
+ XK_Kcedilla = 0x03d3, /* U+0136 LATIN CAPITAL LETTER K WITH CEDILLA */
+ XK_Uogonek = 0x03d9, /* U+0172 LATIN CAPITAL LETTER U WITH OGONEK */
+ XK_Utilde = 0x03dd, /* U+0168 LATIN CAPITAL LETTER U WITH TILDE */
+ XK_Umacron = 0x03de, /* U+016A LATIN CAPITAL LETTER U WITH MACRON */
+ XK_amacron = 0x03e0, /* U+0101 LATIN SMALL LETTER A WITH MACRON */
+ XK_iogonek = 0x03e7, /* U+012F LATIN SMALL LETTER I WITH OGONEK */
+ XK_eabovedot = 0x03ec, /* U+0117 LATIN SMALL LETTER E WITH DOT ABOVE */
+ XK_imacron = 0x03ef, /* U+012B LATIN SMALL LETTER I WITH MACRON */
+ XK_ncedilla = 0x03f1, /* U+0146 LATIN SMALL LETTER N WITH CEDILLA */
+ XK_omacron = 0x03f2, /* U+014D LATIN SMALL LETTER O WITH MACRON */
+ XK_kcedilla = 0x03f3, /* U+0137 LATIN SMALL LETTER K WITH CEDILLA */
+ XK_uogonek = 0x03f9, /* U+0173 LATIN SMALL LETTER U WITH OGONEK */
+ XK_utilde = 0x03fd, /* U+0169 LATIN SMALL LETTER U WITH TILDE */
+ XK_umacron = 0x03fe, /* U+016B LATIN SMALL LETTER U WITH MACRON */
+ XK_Babovedot = 0x1001e02, /* U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE */
+ XK_babovedot = 0x1001e03, /* U+1E03 LATIN SMALL LETTER B WITH DOT ABOVE */
+ XK_Dabovedot = 0x1001e0a, /* U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE */
+ XK_Wgrave = 0x1001e80, /* U+1E80 LATIN CAPITAL LETTER W WITH GRAVE */
+ XK_Wacute = 0x1001e82, /* U+1E82 LATIN CAPITAL LETTER W WITH ACUTE */
+ XK_dabovedot = 0x1001e0b, /* U+1E0B LATIN SMALL LETTER D WITH DOT ABOVE */
+ XK_Ygrave = 0x1001ef2, /* U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE */
+ XK_Fabovedot = 0x1001e1e, /* U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE */
+ XK_fabovedot = 0x1001e1f, /* U+1E1F LATIN SMALL LETTER F WITH DOT ABOVE */
+ XK_Mabovedot = 0x1001e40, /* U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE */
+ XK_mabovedot = 0x1001e41, /* U+1E41 LATIN SMALL LETTER M WITH DOT ABOVE */
+ XK_Pabovedot = 0x1001e56, /* U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE */
+ XK_wgrave = 0x1001e81, /* U+1E81 LATIN SMALL LETTER W WITH GRAVE */
+ XK_pabovedot = 0x1001e57, /* U+1E57 LATIN SMALL LETTER P WITH DOT ABOVE */
+ XK_wacute = 0x1001e83, /* U+1E83 LATIN SMALL LETTER W WITH ACUTE */
+ XK_Sabovedot = 0x1001e60, /* U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE */
+ XK_ygrave = 0x1001ef3, /* U+1EF3 LATIN SMALL LETTER Y WITH GRAVE */
+ XK_Wdiaeresis = 0x1001e84, /* U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS */
+ XK_wdiaeresis = 0x1001e85, /* U+1E85 LATIN SMALL LETTER W WITH DIAERESIS */
+ XK_sabovedot = 0x1001e61, /* U+1E61 LATIN SMALL LETTER S WITH DOT ABOVE */
+ XK_Wcircumflex = 0x1000174, /* U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
+ XK_Tabovedot = 0x1001e6a, /* U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE */
+ XK_Ycircumflex = 0x1000176, /* U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
+ XK_wcircumflex = 0x1000175, /* U+0175 LATIN SMALL LETTER W WITH CIRCUMFLEX */
+ XK_tabovedot = 0x1001e6b, /* U+1E6B LATIN SMALL LETTER T WITH DOT ABOVE */
+ XK_ycircumflex = 0x1000177, /* U+0177 LATIN SMALL LETTER Y WITH CIRCUMFLEX */
+ XK_OE = 0x13bc, /* U+0152 LATIN CAPITAL LIGATURE OE */
+ XK_oe = 0x13bd, /* U+0153 LATIN SMALL LIGATURE OE */
+ XK_Ydiaeresis = 0x13be, /* U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ XK_overline = 0x047e, /* U+203E OVERLINE */
+ XK_kana_fullstop = 0x04a1, /* U+3002 IDEOGRAPHIC FULL STOP */
+ XK_kana_openingbracket = 0x04a2, /* U+300C LEFT CORNER BRACKET */
+ XK_kana_closingbracket = 0x04a3, /* U+300D RIGHT CORNER BRACKET */
+ XK_kana_comma = 0x04a4, /* U+3001 IDEOGRAPHIC COMMA */
+ XK_kana_conjunctive = 0x04a5, /* U+30FB KATAKANA MIDDLE DOT */
+ XK_kana_middledot = 0x04a5, /* deprecated */
+ XK_kana_WO = 0x04a6, /* U+30F2 KATAKANA LETTER WO */
+ XK_kana_a = 0x04a7, /* U+30A1 KATAKANA LETTER SMALL A */
+ XK_kana_i = 0x04a8, /* U+30A3 KATAKANA LETTER SMALL I */
+ XK_kana_u = 0x04a9, /* U+30A5 KATAKANA LETTER SMALL U */
+ XK_kana_e = 0x04aa, /* U+30A7 KATAKANA LETTER SMALL E */
+ XK_kana_o = 0x04ab, /* U+30A9 KATAKANA LETTER SMALL O */
+ XK_kana_ya = 0x04ac, /* U+30E3 KATAKANA LETTER SMALL YA */
+ XK_kana_yu = 0x04ad, /* U+30E5 KATAKANA LETTER SMALL YU */
+ XK_kana_yo = 0x04ae, /* U+30E7 KATAKANA LETTER SMALL YO */
+ XK_kana_tsu = 0x04af, /* U+30C3 KATAKANA LETTER SMALL TU */
+ XK_kana_tu = 0x04af, /* deprecated */
+ XK_prolongedsound = 0x04b0, /* U+30FC KATAKANA-HIRAGANA PROLONGED SOUND MARK */
+ XK_kana_A = 0x04b1, /* U+30A2 KATAKANA LETTER A */
+ XK_kana_I = 0x04b2, /* U+30A4 KATAKANA LETTER I */
+ XK_kana_U = 0x04b3, /* U+30A6 KATAKANA LETTER U */
+ XK_kana_E = 0x04b4, /* U+30A8 KATAKANA LETTER E */
+ XK_kana_O = 0x04b5, /* U+30AA KATAKANA LETTER O */
+ XK_kana_KA = 0x04b6, /* U+30AB KATAKANA LETTER KA */
+ XK_kana_KI = 0x04b7, /* U+30AD KATAKANA LETTER KI */
+ XK_kana_KU = 0x04b8, /* U+30AF KATAKANA LETTER KU */
+ XK_kana_KE = 0x04b9, /* U+30B1 KATAKANA LETTER KE */
+ XK_kana_KO = 0x04ba, /* U+30B3 KATAKANA LETTER KO */
+ XK_kana_SA = 0x04bb, /* U+30B5 KATAKANA LETTER SA */
+ XK_kana_SHI = 0x04bc, /* U+30B7 KATAKANA LETTER SI */
+ XK_kana_SU = 0x04bd, /* U+30B9 KATAKANA LETTER SU */
+ XK_kana_SE = 0x04be, /* U+30BB KATAKANA LETTER SE */
+ XK_kana_SO = 0x04bf, /* U+30BD KATAKANA LETTER SO */
+ XK_kana_TA = 0x04c0, /* U+30BF KATAKANA LETTER TA */
+ XK_kana_CHI = 0x04c1, /* U+30C1 KATAKANA LETTER TI */
+ XK_kana_TI = 0x04c1, /* deprecated */
+ XK_kana_TSU = 0x04c2, /* U+30C4 KATAKANA LETTER TU */
+ XK_kana_TU = 0x04c2, /* deprecated */
+ XK_kana_TE = 0x04c3, /* U+30C6 KATAKANA LETTER TE */
+ XK_kana_TO = 0x04c4, /* U+30C8 KATAKANA LETTER TO */
+ XK_kana_NA = 0x04c5, /* U+30CA KATAKANA LETTER NA */
+ XK_kana_NI = 0x04c6, /* U+30CB KATAKANA LETTER NI */
+ XK_kana_NU = 0x04c7, /* U+30CC KATAKANA LETTER NU */
+ XK_kana_NE = 0x04c8, /* U+30CD KATAKANA LETTER NE */
+ XK_kana_NO = 0x04c9, /* U+30CE KATAKANA LETTER NO */
+ XK_kana_HA = 0x04ca, /* U+30CF KATAKANA LETTER HA */
+ XK_kana_HI = 0x04cb, /* U+30D2 KATAKANA LETTER HI */
+ XK_kana_FU = 0x04cc, /* U+30D5 KATAKANA LETTER HU */
+ XK_kana_HU = 0x04cc, /* deprecated */
+ XK_kana_HE = 0x04cd, /* U+30D8 KATAKANA LETTER HE */
+ XK_kana_HO = 0x04ce, /* U+30DB KATAKANA LETTER HO */
+ XK_kana_MA = 0x04cf, /* U+30DE KATAKANA LETTER MA */
+ XK_kana_MI = 0x04d0, /* U+30DF KATAKANA LETTER MI */
+ XK_kana_MU = 0x04d1, /* U+30E0 KATAKANA LETTER MU */
+ XK_kana_ME = 0x04d2, /* U+30E1 KATAKANA LETTER ME */
+ XK_kana_MO = 0x04d3, /* U+30E2 KATAKANA LETTER MO */
+ XK_kana_YA = 0x04d4, /* U+30E4 KATAKANA LETTER YA */
+ XK_kana_YU = 0x04d5, /* U+30E6 KATAKANA LETTER YU */
+ XK_kana_YO = 0x04d6, /* U+30E8 KATAKANA LETTER YO */
+ XK_kana_RA = 0x04d7, /* U+30E9 KATAKANA LETTER RA */
+ XK_kana_RI = 0x04d8, /* U+30EA KATAKANA LETTER RI */
+ XK_kana_RU = 0x04d9, /* U+30EB KATAKANA LETTER RU */
+ XK_kana_RE = 0x04da, /* U+30EC KATAKANA LETTER RE */
+ XK_kana_RO = 0x04db, /* U+30ED KATAKANA LETTER RO */
+ XK_kana_WA = 0x04dc, /* U+30EF KATAKANA LETTER WA */
+ XK_kana_N = 0x04dd, /* U+30F3 KATAKANA LETTER N */
+ XK_voicedsound = 0x04de, /* U+309B KATAKANA-HIRAGANA VOICED SOUND MARK */
+ XK_semivoicedsound = 0x04df, /* U+309C KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+ XK_kana_switch = 0xff7e, /* Alias for mode_switch */
+ XK_Farsi_0 = 0x10006f0, /* U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO */
+ XK_Farsi_1 = 0x10006f1, /* U+06F1 EXTENDED ARABIC-INDIC DIGIT ONE */
+ XK_Farsi_2 = 0x10006f2, /* U+06F2 EXTENDED ARABIC-INDIC DIGIT TWO */
+ XK_Farsi_3 = 0x10006f3, /* U+06F3 EXTENDED ARABIC-INDIC DIGIT THREE */
+ XK_Farsi_4 = 0x10006f4, /* U+06F4 EXTENDED ARABIC-INDIC DIGIT FOUR */
+ XK_Farsi_5 = 0x10006f5, /* U+06F5 EXTENDED ARABIC-INDIC DIGIT FIVE */
+ XK_Farsi_6 = 0x10006f6, /* U+06F6 EXTENDED ARABIC-INDIC DIGIT SIX */
+ XK_Farsi_7 = 0x10006f7, /* U+06F7 EXTENDED ARABIC-INDIC DIGIT SEVEN */
+ XK_Farsi_8 = 0x10006f8, /* U+06F8 EXTENDED ARABIC-INDIC DIGIT EIGHT */
+ XK_Farsi_9 = 0x10006f9, /* U+06F9 EXTENDED ARABIC-INDIC DIGIT NINE */
+ XK_Arabic_percent = 0x100066a, /* U+066A ARABIC PERCENT SIGN */
+ XK_Arabic_superscript_alef = 0x1000670, /* U+0670 ARABIC LETTER SUPERSCRIPT ALEF */
+ XK_Arabic_tteh = 0x1000679, /* U+0679 ARABIC LETTER TTEH */
+ XK_Arabic_peh = 0x100067e, /* U+067E ARABIC LETTER PEH */
+ XK_Arabic_tcheh = 0x1000686, /* U+0686 ARABIC LETTER TCHEH */
+ XK_Arabic_ddal = 0x1000688, /* U+0688 ARABIC LETTER DDAL */
+ XK_Arabic_rreh = 0x1000691, /* U+0691 ARABIC LETTER RREH */
+ XK_Arabic_comma = 0x05ac, /* U+060C ARABIC COMMA */
+ XK_Arabic_fullstop = 0x10006d4, /* U+06D4 ARABIC FULL STOP */
+ XK_Arabic_0 = 0x1000660, /* U+0660 ARABIC-INDIC DIGIT ZERO */
+ XK_Arabic_1 = 0x1000661, /* U+0661 ARABIC-INDIC DIGIT ONE */
+ XK_Arabic_2 = 0x1000662, /* U+0662 ARABIC-INDIC DIGIT TWO */
+ XK_Arabic_3 = 0x1000663, /* U+0663 ARABIC-INDIC DIGIT THREE */
+ XK_Arabic_4 = 0x1000664, /* U+0664 ARABIC-INDIC DIGIT FOUR */
+ XK_Arabic_5 = 0x1000665, /* U+0665 ARABIC-INDIC DIGIT FIVE */
+ XK_Arabic_6 = 0x1000666, /* U+0666 ARABIC-INDIC DIGIT SIX */
+ XK_Arabic_7 = 0x1000667, /* U+0667 ARABIC-INDIC DIGIT SEVEN */
+ XK_Arabic_8 = 0x1000668, /* U+0668 ARABIC-INDIC DIGIT EIGHT */
+ XK_Arabic_9 = 0x1000669, /* U+0669 ARABIC-INDIC DIGIT NINE */
+ XK_Arabic_semicolon = 0x05bb, /* U+061B ARABIC SEMICOLON */
+ XK_Arabic_question_mark = 0x05bf, /* U+061F ARABIC QUESTION MARK */
+ XK_Arabic_hamza = 0x05c1, /* U+0621 ARABIC LETTER HAMZA */
+ XK_Arabic_maddaonalef = 0x05c2, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
+ XK_Arabic_hamzaonalef = 0x05c3, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
+ XK_Arabic_hamzaonwaw = 0x05c4, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
+ XK_Arabic_hamzaunderalef = 0x05c5, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
+ XK_Arabic_hamzaonyeh = 0x05c6, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
+ XK_Arabic_alef = 0x05c7, /* U+0627 ARABIC LETTER ALEF */
+ XK_Arabic_beh = 0x05c8, /* U+0628 ARABIC LETTER BEH */
+ XK_Arabic_tehmarbuta = 0x05c9, /* U+0629 ARABIC LETTER TEH MARBUTA */
+ XK_Arabic_teh = 0x05ca, /* U+062A ARABIC LETTER TEH */
+ XK_Arabic_theh = 0x05cb, /* U+062B ARABIC LETTER THEH */
+ XK_Arabic_jeem = 0x05cc, /* U+062C ARABIC LETTER JEEM */
+ XK_Arabic_hah = 0x05cd, /* U+062D ARABIC LETTER HAH */
+ XK_Arabic_khah = 0x05ce, /* U+062E ARABIC LETTER KHAH */
+ XK_Arabic_dal = 0x05cf, /* U+062F ARABIC LETTER DAL */
+ XK_Arabic_thal = 0x05d0, /* U+0630 ARABIC LETTER THAL */
+ XK_Arabic_ra = 0x05d1, /* U+0631 ARABIC LETTER REH */
+ XK_Arabic_zain = 0x05d2, /* U+0632 ARABIC LETTER ZAIN */
+ XK_Arabic_seen = 0x05d3, /* U+0633 ARABIC LETTER SEEN */
+ XK_Arabic_sheen = 0x05d4, /* U+0634 ARABIC LETTER SHEEN */
+ XK_Arabic_sad = 0x05d5, /* U+0635 ARABIC LETTER SAD */
+ XK_Arabic_dad = 0x05d6, /* U+0636 ARABIC LETTER DAD */
+ XK_Arabic_tah = 0x05d7, /* U+0637 ARABIC LETTER TAH */
+ XK_Arabic_zah = 0x05d8, /* U+0638 ARABIC LETTER ZAH */
+ XK_Arabic_ain = 0x05d9, /* U+0639 ARABIC LETTER AIN */
+ XK_Arabic_ghain = 0x05da, /* U+063A ARABIC LETTER GHAIN */
+ XK_Arabic_tatweel = 0x05e0, /* U+0640 ARABIC TATWEEL */
+ XK_Arabic_feh = 0x05e1, /* U+0641 ARABIC LETTER FEH */
+ XK_Arabic_qaf = 0x05e2, /* U+0642 ARABIC LETTER QAF */
+ XK_Arabic_kaf = 0x05e3, /* U+0643 ARABIC LETTER KAF */
+ XK_Arabic_lam = 0x05e4, /* U+0644 ARABIC LETTER LAM */
+ XK_Arabic_meem = 0x05e5, /* U+0645 ARABIC LETTER MEEM */
+ XK_Arabic_noon = 0x05e6, /* U+0646 ARABIC LETTER NOON */
+ XK_Arabic_ha = 0x05e7, /* U+0647 ARABIC LETTER HEH */
+ XK_Arabic_heh = 0x05e7, /* deprecated */
+ XK_Arabic_waw = 0x05e8, /* U+0648 ARABIC LETTER WAW */
+ XK_Arabic_alefmaksura = 0x05e9, /* U+0649 ARABIC LETTER ALEF MAKSURA */
+ XK_Arabic_yeh = 0x05ea, /* U+064A ARABIC LETTER YEH */
+ XK_Arabic_fathatan = 0x05eb, /* U+064B ARABIC FATHATAN */
+ XK_Arabic_dammatan = 0x05ec, /* U+064C ARABIC DAMMATAN */
+ XK_Arabic_kasratan = 0x05ed, /* U+064D ARABIC KASRATAN */
+ XK_Arabic_fatha = 0x05ee, /* U+064E ARABIC FATHA */
+ XK_Arabic_damma = 0x05ef, /* U+064F ARABIC DAMMA */
+ XK_Arabic_kasra = 0x05f0, /* U+0650 ARABIC KASRA */
+ XK_Arabic_shadda = 0x05f1, /* U+0651 ARABIC SHADDA */
+ XK_Arabic_sukun = 0x05f2, /* U+0652 ARABIC SUKUN */
+ XK_Arabic_madda_above = 0x1000653, /* U+0653 ARABIC MADDAH ABOVE */
+ XK_Arabic_hamza_above = 0x1000654, /* U+0654 ARABIC HAMZA ABOVE */
+ XK_Arabic_hamza_below = 0x1000655, /* U+0655 ARABIC HAMZA BELOW */
+ XK_Arabic_jeh = 0x1000698, /* U+0698 ARABIC LETTER JEH */
+ XK_Arabic_veh = 0x10006a4, /* U+06A4 ARABIC LETTER VEH */
+ XK_Arabic_keheh = 0x10006a9, /* U+06A9 ARABIC LETTER KEHEH */
+ XK_Arabic_gaf = 0x10006af, /* U+06AF ARABIC LETTER GAF */
+ XK_Arabic_noon_ghunna = 0x10006ba, /* U+06BA ARABIC LETTER NOON GHUNNA */
+ XK_Arabic_heh_doachashmee = 0x10006be, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
+ XK_Farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */
+ XK_Arabic_farsi_yeh = 0x10006cc, /* U+06CC ARABIC LETTER FARSI YEH */
+ XK_Arabic_yeh_baree = 0x10006d2, /* U+06D2 ARABIC LETTER YEH BARREE */
+ XK_Arabic_heh_goal = 0x10006c1, /* U+06C1 ARABIC LETTER HEH GOAL */
+ XK_Arabic_switch = 0xff7e, /* Alias for mode_switch */
+ XK_Cyrillic_GHE_bar = 0x1000492, /* U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE */
+ XK_Cyrillic_ghe_bar = 0x1000493, /* U+0493 CYRILLIC SMALL LETTER GHE WITH STROKE */
+ XK_Cyrillic_ZHE_descender = 0x1000496, /* U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */
+ XK_Cyrillic_zhe_descender = 0x1000497, /* U+0497 CYRILLIC SMALL LETTER ZHE WITH DESCENDER */
+ XK_Cyrillic_KA_descender = 0x100049a, /* U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER */
+ XK_Cyrillic_ka_descender = 0x100049b, /* U+049B CYRILLIC SMALL LETTER KA WITH DESCENDER */
+ XK_Cyrillic_KA_vertstroke = 0x100049c, /* U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */
+ XK_Cyrillic_ka_vertstroke = 0x100049d, /* U+049D CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */
+ XK_Cyrillic_EN_descender = 0x10004a2, /* U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER */
+ XK_Cyrillic_en_descender = 0x10004a3, /* U+04A3 CYRILLIC SMALL LETTER EN WITH DESCENDER */
+ XK_Cyrillic_U_straight = 0x10004ae, /* U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U */
+ XK_Cyrillic_u_straight = 0x10004af, /* U+04AF CYRILLIC SMALL LETTER STRAIGHT U */
+ XK_Cyrillic_U_straight_bar = 0x10004b0, /* U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */
+ XK_Cyrillic_u_straight_bar = 0x10004b1, /* U+04B1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */
+ XK_Cyrillic_HA_descender = 0x10004b2, /* U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER */
+ XK_Cyrillic_ha_descender = 0x10004b3, /* U+04B3 CYRILLIC SMALL LETTER HA WITH DESCENDER */
+ XK_Cyrillic_CHE_descender = 0x10004b6, /* U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */
+ XK_Cyrillic_che_descender = 0x10004b7, /* U+04B7 CYRILLIC SMALL LETTER CHE WITH DESCENDER */
+ XK_Cyrillic_CHE_vertstroke = 0x10004b8, /* U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */
+ XK_Cyrillic_che_vertstroke = 0x10004b9, /* U+04B9 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */
+ XK_Cyrillic_SHHA = 0x10004ba, /* U+04BA CYRILLIC CAPITAL LETTER SHHA */
+ XK_Cyrillic_shha = 0x10004bb, /* U+04BB CYRILLIC SMALL LETTER SHHA */
+ XK_Cyrillic_SCHWA = 0x10004d8, /* U+04D8 CYRILLIC CAPITAL LETTER SCHWA */
+ XK_Cyrillic_schwa = 0x10004d9, /* U+04D9 CYRILLIC SMALL LETTER SCHWA */
+ XK_Cyrillic_I_macron = 0x10004e2, /* U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON */
+ XK_Cyrillic_i_macron = 0x10004e3, /* U+04E3 CYRILLIC SMALL LETTER I WITH MACRON */
+ XK_Cyrillic_O_bar = 0x10004e8, /* U+04E8 CYRILLIC CAPITAL LETTER BARRED O */
+ XK_Cyrillic_o_bar = 0x10004e9, /* U+04E9 CYRILLIC SMALL LETTER BARRED O */
+ XK_Cyrillic_U_macron = 0x10004ee, /* U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON */
+ XK_Cyrillic_u_macron = 0x10004ef, /* U+04EF CYRILLIC SMALL LETTER U WITH MACRON */
+ XK_Serbian_dje = 0x06a1, /* U+0452 CYRILLIC SMALL LETTER DJE */
+ XK_Macedonia_gje = 0x06a2, /* U+0453 CYRILLIC SMALL LETTER GJE */
+ XK_Cyrillic_io = 0x06a3, /* U+0451 CYRILLIC SMALL LETTER IO */
+ XK_Ukrainian_ie = 0x06a4, /* U+0454 CYRILLIC SMALL LETTER UKRAINIAN IE */
+ XK_Ukranian_je = 0x06a4, /* deprecated */
+ XK_Macedonia_dse = 0x06a5, /* U+0455 CYRILLIC SMALL LETTER DZE */
+ XK_Ukrainian_i = 0x06a6, /* U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+ XK_Ukranian_i = 0x06a6, /* deprecated */
+ XK_Ukrainian_yi = 0x06a7, /* U+0457 CYRILLIC SMALL LETTER YI */
+ XK_Ukranian_yi = 0x06a7, /* deprecated */
+ XK_Cyrillic_je = 0x06a8, /* U+0458 CYRILLIC SMALL LETTER JE */
+ XK_Serbian_je = 0x06a8, /* deprecated */
+ XK_Cyrillic_lje = 0x06a9, /* U+0459 CYRILLIC SMALL LETTER LJE */
+ XK_Serbian_lje = 0x06a9, /* deprecated */
+ XK_Cyrillic_nje = 0x06aa, /* U+045A CYRILLIC SMALL LETTER NJE */
+ XK_Serbian_nje = 0x06aa, /* deprecated */
+ XK_Serbian_tshe = 0x06ab, /* U+045B CYRILLIC SMALL LETTER TSHE */
+ XK_Macedonia_kje = 0x06ac, /* U+045C CYRILLIC SMALL LETTER KJE */
+ XK_Ukrainian_ghe_with_upturn = 0x06ad, /* U+0491 CYRILLIC SMALL LETTER GHE WITH UPTURN */
+ XK_Byelorussian_shortu = 0x06ae, /* U+045E CYRILLIC SMALL LETTER SHORT U */
+ XK_Cyrillic_dzhe = 0x06af, /* U+045F CYRILLIC SMALL LETTER DZHE */
+ XK_Serbian_dze = 0x06af, /* deprecated */
+ XK_numerosign = 0x06b0, /* U+2116 NUMERO SIGN */
+ XK_Serbian_DJE = 0x06b1, /* U+0402 CYRILLIC CAPITAL LETTER DJE */
+ XK_Macedonia_GJE = 0x06b2, /* U+0403 CYRILLIC CAPITAL LETTER GJE */
+ XK_Cyrillic_IO = 0x06b3, /* U+0401 CYRILLIC CAPITAL LETTER IO */
+ XK_Ukrainian_IE = 0x06b4, /* U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+ XK_Ukranian_JE = 0x06b4, /* deprecated */
+ XK_Macedonia_DSE = 0x06b5, /* U+0405 CYRILLIC CAPITAL LETTER DZE */
+ XK_Ukrainian_I = 0x06b6, /* U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+ XK_Ukranian_I = 0x06b6, /* deprecated */
+ XK_Ukrainian_YI = 0x06b7, /* U+0407 CYRILLIC CAPITAL LETTER YI */
+ XK_Ukranian_YI = 0x06b7, /* deprecated */
+ XK_Cyrillic_JE = 0x06b8, /* U+0408 CYRILLIC CAPITAL LETTER JE */
+ XK_Serbian_JE = 0x06b8, /* deprecated */
+ XK_Cyrillic_LJE = 0x06b9, /* U+0409 CYRILLIC CAPITAL LETTER LJE */
+ XK_Serbian_LJE = 0x06b9, /* deprecated */
+ XK_Cyrillic_NJE = 0x06ba, /* U+040A CYRILLIC CAPITAL LETTER NJE */
+ XK_Serbian_NJE = 0x06ba, /* deprecated */
+ XK_Serbian_TSHE = 0x06bb, /* U+040B CYRILLIC CAPITAL LETTER TSHE */
+ XK_Macedonia_KJE = 0x06bc, /* U+040C CYRILLIC CAPITAL LETTER KJE */
+ XK_Ukrainian_GHE_WITH_UPTURN = 0x06bd, /* U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
+ XK_Byelorussian_SHORTU = 0x06be, /* U+040E CYRILLIC CAPITAL LETTER SHORT U */
+ XK_Cyrillic_DZHE = 0x06bf, /* U+040F CYRILLIC CAPITAL LETTER DZHE */
+ XK_Serbian_DZE = 0x06bf, /* deprecated */
+ XK_Cyrillic_yu = 0x06c0, /* U+044E CYRILLIC SMALL LETTER YU */
+ XK_Cyrillic_a = 0x06c1, /* U+0430 CYRILLIC SMALL LETTER A */
+ XK_Cyrillic_be = 0x06c2, /* U+0431 CYRILLIC SMALL LETTER BE */
+ XK_Cyrillic_tse = 0x06c3, /* U+0446 CYRILLIC SMALL LETTER TSE */
+ XK_Cyrillic_de = 0x06c4, /* U+0434 CYRILLIC SMALL LETTER DE */
+ XK_Cyrillic_ie = 0x06c5, /* U+0435 CYRILLIC SMALL LETTER IE */
+ XK_Cyrillic_ef = 0x06c6, /* U+0444 CYRILLIC SMALL LETTER EF */
+ XK_Cyrillic_ghe = 0x06c7, /* U+0433 CYRILLIC SMALL LETTER GHE */
+ XK_Cyrillic_ha = 0x06c8, /* U+0445 CYRILLIC SMALL LETTER HA */
+ XK_Cyrillic_i = 0x06c9, /* U+0438 CYRILLIC SMALL LETTER I */
+ XK_Cyrillic_shorti = 0x06ca, /* U+0439 CYRILLIC SMALL LETTER SHORT I */
+ XK_Cyrillic_ka = 0x06cb, /* U+043A CYRILLIC SMALL LETTER KA */
+ XK_Cyrillic_el = 0x06cc, /* U+043B CYRILLIC SMALL LETTER EL */
+ XK_Cyrillic_em = 0x06cd, /* U+043C CYRILLIC SMALL LETTER EM */
+ XK_Cyrillic_en = 0x06ce, /* U+043D CYRILLIC SMALL LETTER EN */
+ XK_Cyrillic_o = 0x06cf, /* U+043E CYRILLIC SMALL LETTER O */
+ XK_Cyrillic_pe = 0x06d0, /* U+043F CYRILLIC SMALL LETTER PE */
+ XK_Cyrillic_ya = 0x06d1, /* U+044F CYRILLIC SMALL LETTER YA */
+ XK_Cyrillic_er = 0x06d2, /* U+0440 CYRILLIC SMALL LETTER ER */
+ XK_Cyrillic_es = 0x06d3, /* U+0441 CYRILLIC SMALL LETTER ES */
+ XK_Cyrillic_te = 0x06d4, /* U+0442 CYRILLIC SMALL LETTER TE */
+ XK_Cyrillic_u = 0x06d5, /* U+0443 CYRILLIC SMALL LETTER U */
+ XK_Cyrillic_zhe = 0x06d6, /* U+0436 CYRILLIC SMALL LETTER ZHE */
+ XK_Cyrillic_ve = 0x06d7, /* U+0432 CYRILLIC SMALL LETTER VE */
+ XK_Cyrillic_softsign = 0x06d8, /* U+044C CYRILLIC SMALL LETTER SOFT SIGN */
+ XK_Cyrillic_yeru = 0x06d9, /* U+044B CYRILLIC SMALL LETTER YERU */
+ XK_Cyrillic_ze = 0x06da, /* U+0437 CYRILLIC SMALL LETTER ZE */
+ XK_Cyrillic_sha = 0x06db, /* U+0448 CYRILLIC SMALL LETTER SHA */
+ XK_Cyrillic_e = 0x06dc, /* U+044D CYRILLIC SMALL LETTER E */
+ XK_Cyrillic_shcha = 0x06dd, /* U+0449 CYRILLIC SMALL LETTER SHCHA */
+ XK_Cyrillic_che = 0x06de, /* U+0447 CYRILLIC SMALL LETTER CHE */
+ XK_Cyrillic_hardsign = 0x06df, /* U+044A CYRILLIC SMALL LETTER HARD SIGN */
+ XK_Cyrillic_YU = 0x06e0, /* U+042E CYRILLIC CAPITAL LETTER YU */
+ XK_Cyrillic_A = 0x06e1, /* U+0410 CYRILLIC CAPITAL LETTER A */
+ XK_Cyrillic_BE = 0x06e2, /* U+0411 CYRILLIC CAPITAL LETTER BE */
+ XK_Cyrillic_TSE = 0x06e3, /* U+0426 CYRILLIC CAPITAL LETTER TSE */
+ XK_Cyrillic_DE = 0x06e4, /* U+0414 CYRILLIC CAPITAL LETTER DE */
+ XK_Cyrillic_IE = 0x06e5, /* U+0415 CYRILLIC CAPITAL LETTER IE */
+ XK_Cyrillic_EF = 0x06e6, /* U+0424 CYRILLIC CAPITAL LETTER EF */
+ XK_Cyrillic_GHE = 0x06e7, /* U+0413 CYRILLIC CAPITAL LETTER GHE */
+ XK_Cyrillic_HA = 0x06e8, /* U+0425 CYRILLIC CAPITAL LETTER HA */
+ XK_Cyrillic_I = 0x06e9, /* U+0418 CYRILLIC CAPITAL LETTER I */
+ XK_Cyrillic_SHORTI = 0x06ea, /* U+0419 CYRILLIC CAPITAL LETTER SHORT I */
+ XK_Cyrillic_KA = 0x06eb, /* U+041A CYRILLIC CAPITAL LETTER KA */
+ XK_Cyrillic_EL = 0x06ec, /* U+041B CYRILLIC CAPITAL LETTER EL */
+ XK_Cyrillic_EM = 0x06ed, /* U+041C CYRILLIC CAPITAL LETTER EM */
+ XK_Cyrillic_EN = 0x06ee, /* U+041D CYRILLIC CAPITAL LETTER EN */
+ XK_Cyrillic_O = 0x06ef, /* U+041E CYRILLIC CAPITAL LETTER O */
+ XK_Cyrillic_PE = 0x06f0, /* U+041F CYRILLIC CAPITAL LETTER PE */
+ XK_Cyrillic_YA = 0x06f1, /* U+042F CYRILLIC CAPITAL LETTER YA */
+ XK_Cyrillic_ER = 0x06f2, /* U+0420 CYRILLIC CAPITAL LETTER ER */
+ XK_Cyrillic_ES = 0x06f3, /* U+0421 CYRILLIC CAPITAL LETTER ES */
+ XK_Cyrillic_TE = 0x06f4, /* U+0422 CYRILLIC CAPITAL LETTER TE */
+ XK_Cyrillic_U = 0x06f5, /* U+0423 CYRILLIC CAPITAL LETTER U */
+ XK_Cyrillic_ZHE = 0x06f6, /* U+0416 CYRILLIC CAPITAL LETTER ZHE */
+ XK_Cyrillic_VE = 0x06f7, /* U+0412 CYRILLIC CAPITAL LETTER VE */
+ XK_Cyrillic_SOFTSIGN = 0x06f8, /* U+042C CYRILLIC CAPITAL LETTER SOFT SIGN */
+ XK_Cyrillic_YERU = 0x06f9, /* U+042B CYRILLIC CAPITAL LETTER YERU */
+ XK_Cyrillic_ZE = 0x06fa, /* U+0417 CYRILLIC CAPITAL LETTER ZE */
+ XK_Cyrillic_SHA = 0x06fb, /* U+0428 CYRILLIC CAPITAL LETTER SHA */
+ XK_Cyrillic_E = 0x06fc, /* U+042D CYRILLIC CAPITAL LETTER E */
+ XK_Cyrillic_SHCHA = 0x06fd, /* U+0429 CYRILLIC CAPITAL LETTER SHCHA */
+ XK_Cyrillic_CHE = 0x06fe, /* U+0427 CYRILLIC CAPITAL LETTER CHE */
+ XK_Cyrillic_HARDSIGN = 0x06ff, /* U+042A CYRILLIC CAPITAL LETTER HARD SIGN */
+ XK_Greek_ALPHAaccent = 0x07a1, /* U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS */
+ XK_Greek_EPSILONaccent = 0x07a2, /* U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS */
+ XK_Greek_ETAaccent = 0x07a3, /* U+0389 GREEK CAPITAL LETTER ETA WITH TONOS */
+ XK_Greek_IOTAaccent = 0x07a4, /* U+038A GREEK CAPITAL LETTER IOTA WITH TONOS */
+ XK_Greek_IOTAdieresis = 0x07a5, /* U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+ XK_Greek_IOTAdiaeresis = 0x07a5, /* old typo */
+ XK_Greek_OMICRONaccent = 0x07a7, /* U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS */
+ XK_Greek_UPSILONaccent = 0x07a8, /* U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS */
+ XK_Greek_UPSILONdieresis = 0x07a9, /* U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+ XK_Greek_OMEGAaccent = 0x07ab, /* U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS */
+ XK_Greek_accentdieresis = 0x07ae, /* U+0385 GREEK DIALYTIKA TONOS */
+ XK_Greek_horizbar = 0x07af, /* U+2015 HORIZONTAL BAR */
+ XK_Greek_alphaaccent = 0x07b1, /* U+03AC GREEK SMALL LETTER ALPHA WITH TONOS */
+ XK_Greek_epsilonaccent = 0x07b2, /* U+03AD GREEK SMALL LETTER EPSILON WITH TONOS */
+ XK_Greek_etaaccent = 0x07b3, /* U+03AE GREEK SMALL LETTER ETA WITH TONOS */
+ XK_Greek_iotaaccent = 0x07b4, /* U+03AF GREEK SMALL LETTER IOTA WITH TONOS */
+ XK_Greek_iotadieresis = 0x07b5, /* U+03CA GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+ XK_Greek_iotaaccentdieresis = 0x07b6, /* U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+ XK_Greek_omicronaccent = 0x07b7, /* U+03CC GREEK SMALL LETTER OMICRON WITH TONOS */
+ XK_Greek_upsilonaccent = 0x07b8, /* U+03CD GREEK SMALL LETTER UPSILON WITH TONOS */
+ XK_Greek_upsilondieresis = 0x07b9, /* U+03CB GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+ XK_Greek_upsilonaccentdieresis = 0x07ba, /* U+03B0 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+ XK_Greek_omegaaccent = 0x07bb, /* U+03CE GREEK SMALL LETTER OMEGA WITH TONOS */
+ XK_Greek_ALPHA = 0x07c1, /* U+0391 GREEK CAPITAL LETTER ALPHA */
+ XK_Greek_BETA = 0x07c2, /* U+0392 GREEK CAPITAL LETTER BETA */
+ XK_Greek_GAMMA = 0x07c3, /* U+0393 GREEK CAPITAL LETTER GAMMA */
+ XK_Greek_DELTA = 0x07c4, /* U+0394 GREEK CAPITAL LETTER DELTA */
+ XK_Greek_EPSILON = 0x07c5, /* U+0395 GREEK CAPITAL LETTER EPSILON */
+ XK_Greek_ZETA = 0x07c6, /* U+0396 GREEK CAPITAL LETTER ZETA */
+ XK_Greek_ETA = 0x07c7, /* U+0397 GREEK CAPITAL LETTER ETA */
+ XK_Greek_THETA = 0x07c8, /* U+0398 GREEK CAPITAL LETTER THETA */
+ XK_Greek_IOTA = 0x07c9, /* U+0399 GREEK CAPITAL LETTER IOTA */
+ XK_Greek_KAPPA = 0x07ca, /* U+039A GREEK CAPITAL LETTER KAPPA */
+ XK_Greek_LAMDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */
+ XK_Greek_LAMBDA = 0x07cb, /* U+039B GREEK CAPITAL LETTER LAMDA */
+ XK_Greek_MU = 0x07cc, /* U+039C GREEK CAPITAL LETTER MU */
+ XK_Greek_NU = 0x07cd, /* U+039D GREEK CAPITAL LETTER NU */
+ XK_Greek_XI = 0x07ce, /* U+039E GREEK CAPITAL LETTER XI */
+ XK_Greek_OMICRON = 0x07cf, /* U+039F GREEK CAPITAL LETTER OMICRON */
+ XK_Greek_PI = 0x07d0, /* U+03A0 GREEK CAPITAL LETTER PI */
+ XK_Greek_RHO = 0x07d1, /* U+03A1 GREEK CAPITAL LETTER RHO */
+ XK_Greek_SIGMA = 0x07d2, /* U+03A3 GREEK CAPITAL LETTER SIGMA */
+ XK_Greek_TAU = 0x07d4, /* U+03A4 GREEK CAPITAL LETTER TAU */
+ XK_Greek_UPSILON = 0x07d5, /* U+03A5 GREEK CAPITAL LETTER UPSILON */
+ XK_Greek_PHI = 0x07d6, /* U+03A6 GREEK CAPITAL LETTER PHI */
+ XK_Greek_CHI = 0x07d7, /* U+03A7 GREEK CAPITAL LETTER CHI */
+ XK_Greek_PSI = 0x07d8, /* U+03A8 GREEK CAPITAL LETTER PSI */
+ XK_Greek_OMEGA = 0x07d9, /* U+03A9 GREEK CAPITAL LETTER OMEGA */
+ XK_Greek_alpha = 0x07e1, /* U+03B1 GREEK SMALL LETTER ALPHA */
+ XK_Greek_beta = 0x07e2, /* U+03B2 GREEK SMALL LETTER BETA */
+ XK_Greek_gamma = 0x07e3, /* U+03B3 GREEK SMALL LETTER GAMMA */
+ XK_Greek_delta = 0x07e4, /* U+03B4 GREEK SMALL LETTER DELTA */
+ XK_Greek_epsilon = 0x07e5, /* U+03B5 GREEK SMALL LETTER EPSILON */
+ XK_Greek_zeta = 0x07e6, /* U+03B6 GREEK SMALL LETTER ZETA */
+ XK_Greek_eta = 0x07e7, /* U+03B7 GREEK SMALL LETTER ETA */
+ XK_Greek_theta = 0x07e8, /* U+03B8 GREEK SMALL LETTER THETA */
+ XK_Greek_iota = 0x07e9, /* U+03B9 GREEK SMALL LETTER IOTA */
+ XK_Greek_kappa = 0x07ea, /* U+03BA GREEK SMALL LETTER KAPPA */
+ XK_Greek_lamda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */
+ XK_Greek_lambda = 0x07eb, /* U+03BB GREEK SMALL LETTER LAMDA */
+ XK_Greek_mu = 0x07ec, /* U+03BC GREEK SMALL LETTER MU */
+ XK_Greek_nu = 0x07ed, /* U+03BD GREEK SMALL LETTER NU */
+ XK_Greek_xi = 0x07ee, /* U+03BE GREEK SMALL LETTER XI */
+ XK_Greek_omicron = 0x07ef, /* U+03BF GREEK SMALL LETTER OMICRON */
+ XK_Greek_pi = 0x07f0, /* U+03C0 GREEK SMALL LETTER PI */
+ XK_Greek_rho = 0x07f1, /* U+03C1 GREEK SMALL LETTER RHO */
+ XK_Greek_sigma = 0x07f2, /* U+03C3 GREEK SMALL LETTER SIGMA */
+ XK_Greek_finalsmallsigma = 0x07f3, /* U+03C2 GREEK SMALL LETTER FINAL SIGMA */
+ XK_Greek_tau = 0x07f4, /* U+03C4 GREEK SMALL LETTER TAU */
+ XK_Greek_upsilon = 0x07f5, /* U+03C5 GREEK SMALL LETTER UPSILON */
+ XK_Greek_phi = 0x07f6, /* U+03C6 GREEK SMALL LETTER PHI */
+ XK_Greek_chi = 0x07f7, /* U+03C7 GREEK SMALL LETTER CHI */
+ XK_Greek_psi = 0x07f8, /* U+03C8 GREEK SMALL LETTER PSI */
+ XK_Greek_omega = 0x07f9, /* U+03C9 GREEK SMALL LETTER OMEGA */
+ XK_Greek_switch = 0xff7e, /* Alias for mode_switch */
+ XK_leftradical = 0x08a1, /* U+23B7 RADICAL SYMBOL BOTTOM */
+ XK_topleftradical = 0x08a2, /*(U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT)*/
+ XK_horizconnector = 0x08a3, /*(U+2500 BOX DRAWINGS LIGHT HORIZONTAL)*/
+ XK_topintegral = 0x08a4, /* U+2320 TOP HALF INTEGRAL */
+ XK_botintegral = 0x08a5, /* U+2321 BOTTOM HALF INTEGRAL */
+ XK_vertconnector = 0x08a6, /*(U+2502 BOX DRAWINGS LIGHT VERTICAL)*/
+ XK_topleftsqbracket = 0x08a7, /* U+23A1 LEFT SQUARE BRACKET UPPER CORNER */
+ XK_botleftsqbracket = 0x08a8, /* U+23A3 LEFT SQUARE BRACKET LOWER CORNER */
+ XK_toprightsqbracket = 0x08a9, /* U+23A4 RIGHT SQUARE BRACKET UPPER CORNER */
+ XK_botrightsqbracket = 0x08aa, /* U+23A6 RIGHT SQUARE BRACKET LOWER CORNER */
+ XK_topleftparens = 0x08ab, /* U+239B LEFT PARENTHESIS UPPER HOOK */
+ XK_botleftparens = 0x08ac, /* U+239D LEFT PARENTHESIS LOWER HOOK */
+ XK_toprightparens = 0x08ad, /* U+239E RIGHT PARENTHESIS UPPER HOOK */
+ XK_botrightparens = 0x08ae, /* U+23A0 RIGHT PARENTHESIS LOWER HOOK */
+ XK_leftmiddlecurlybrace = 0x08af, /* U+23A8 LEFT CURLY BRACKET MIDDLE PIECE */
+ XK_rightmiddlecurlybrace = 0x08b0, /* U+23AC RIGHT CURLY BRACKET MIDDLE PIECE */
+ XK_topleftsummation = 0x08b1,
+ XK_botleftsummation = 0x08b2,
+ XK_topvertsummationconnector = 0x08b3,
+ XK_botvertsummationconnector = 0x08b4,
+ XK_toprightsummation = 0x08b5,
+ XK_botrightsummation = 0x08b6,
+ XK_rightmiddlesummation = 0x08b7,
+ XK_lessthanequal = 0x08bc, /* U+2264 LESS-THAN OR EQUAL TO */
+ XK_notequal = 0x08bd, /* U+2260 NOT EQUAL TO */
+ XK_greaterthanequal = 0x08be, /* U+2265 GREATER-THAN OR EQUAL TO */
+ XK_integral = 0x08bf, /* U+222B INTEGRAL */
+ XK_therefore = 0x08c0, /* U+2234 THEREFORE */
+ XK_variation = 0x08c1, /* U+221D PROPORTIONAL TO */
+ XK_infinity = 0x08c2, /* U+221E INFINITY */
+ XK_nabla = 0x08c5, /* U+2207 NABLA */
+ XK_approximate = 0x08c8, /* U+223C TILDE OPERATOR */
+ XK_similarequal = 0x08c9, /* U+2243 ASYMPTOTICALLY EQUAL TO */
+ XK_ifonlyif = 0x08cd, /* U+21D4 LEFT RIGHT DOUBLE ARROW */
+ XK_implies = 0x08ce, /* U+21D2 RIGHTWARDS DOUBLE ARROW */
+ XK_identical = 0x08cf, /* U+2261 IDENTICAL TO */
+ XK_radical = 0x08d6, /* U+221A SQUARE ROOT */
+ XK_includedin = 0x08da, /* U+2282 SUBSET OF */
+ XK_includes = 0x08db, /* U+2283 SUPERSET OF */
+ XK_intersection = 0x08dc, /* U+2229 INTERSECTION */
+ XK_union = 0x08dd, /* U+222A UNION */
+ XK_logicaland = 0x08de, /* U+2227 LOGICAL AND */
+ XK_logicalor = 0x08df, /* U+2228 LOGICAL OR */
+ XK_partialderivative = 0x08ef, /* U+2202 PARTIAL DIFFERENTIAL */
+ XK_function = 0x08f6, /* U+0192 LATIN SMALL LETTER F WITH HOOK */
+ XK_leftarrow = 0x08fb, /* U+2190 LEFTWARDS ARROW */
+ XK_uparrow = 0x08fc, /* U+2191 UPWARDS ARROW */
+ XK_rightarrow = 0x08fd, /* U+2192 RIGHTWARDS ARROW */
+ XK_downarrow = 0x08fe, /* U+2193 DOWNWARDS ARROW */
+ XK_blank = 0x09df,
+ XK_soliddiamond = 0x09e0, /* U+25C6 BLACK DIAMOND */
+ XK_checkerboard = 0x09e1, /* U+2592 MEDIUM SHADE */
+ XK_ht = 0x09e2, /* U+2409 SYMBOL FOR HORIZONTAL TABULATION */
+ XK_ff = 0x09e3, /* U+240C SYMBOL FOR FORM FEED */
+ XK_cr = 0x09e4, /* U+240D SYMBOL FOR CARRIAGE RETURN */
+ XK_lf = 0x09e5, /* U+240A SYMBOL FOR LINE FEED */
+ XK_nl = 0x09e8, /* U+2424 SYMBOL FOR NEWLINE */
+ XK_vt = 0x09e9, /* U+240B SYMBOL FOR VERTICAL TABULATION */
+ XK_lowrightcorner = 0x09ea, /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */
+ XK_uprightcorner = 0x09eb, /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */
+ XK_upleftcorner = 0x09ec, /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */
+ XK_lowleftcorner = 0x09ed, /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */
+ XK_crossinglines = 0x09ee, /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+ XK_horizlinescan1 = 0x09ef, /* U+23BA HORIZONTAL SCAN LINE-1 */
+ XK_horizlinescan3 = 0x09f0, /* U+23BB HORIZONTAL SCAN LINE-3 */
+ XK_horizlinescan5 = 0x09f1, /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */
+ XK_horizlinescan7 = 0x09f2, /* U+23BC HORIZONTAL SCAN LINE-7 */
+ XK_horizlinescan9 = 0x09f3, /* U+23BD HORIZONTAL SCAN LINE-9 */
+ XK_leftt = 0x09f4, /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ XK_rightt = 0x09f5, /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+ XK_bott = 0x09f6, /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+ XK_topt = 0x09f7, /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+ XK_vertbar = 0x09f8, /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
+ XK_emspace = 0x0aa1, /* U+2003 EM SPACE */
+ XK_enspace = 0x0aa2, /* U+2002 EN SPACE */
+ XK_em3space = 0x0aa3, /* U+2004 THREE-PER-EM SPACE */
+ XK_em4space = 0x0aa4, /* U+2005 FOUR-PER-EM SPACE */
+ XK_digitspace = 0x0aa5, /* U+2007 FIGURE SPACE */
+ XK_punctspace = 0x0aa6, /* U+2008 PUNCTUATION SPACE */
+ XK_thinspace = 0x0aa7, /* U+2009 THIN SPACE */
+ XK_hairspace = 0x0aa8, /* U+200A HAIR SPACE */
+ XK_emdash = 0x0aa9, /* U+2014 EM DASH */
+ XK_endash = 0x0aaa, /* U+2013 EN DASH */
+ XK_signifblank = 0x0aac, /*(U+2423 OPEN BOX)*/
+ XK_ellipsis = 0x0aae, /* U+2026 HORIZONTAL ELLIPSIS */
+ XK_doubbaselinedot = 0x0aaf, /* U+2025 TWO DOT LEADER */
+ XK_onethird = 0x0ab0, /* U+2153 VULGAR FRACTION ONE THIRD */
+ XK_twothirds = 0x0ab1, /* U+2154 VULGAR FRACTION TWO THIRDS */
+ XK_onefifth = 0x0ab2, /* U+2155 VULGAR FRACTION ONE FIFTH */
+ XK_twofifths = 0x0ab3, /* U+2156 VULGAR FRACTION TWO FIFTHS */
+ XK_threefifths = 0x0ab4, /* U+2157 VULGAR FRACTION THREE FIFTHS */
+ XK_fourfifths = 0x0ab5, /* U+2158 VULGAR FRACTION FOUR FIFTHS */
+ XK_onesixth = 0x0ab6, /* U+2159 VULGAR FRACTION ONE SIXTH */
+ XK_fivesixths = 0x0ab7, /* U+215A VULGAR FRACTION FIVE SIXTHS */
+ XK_careof = 0x0ab8, /* U+2105 CARE OF */
+ XK_figdash = 0x0abb, /* U+2012 FIGURE DASH */
+ XK_leftanglebracket = 0x0abc, /*(U+27E8 MATHEMATICAL LEFT ANGLE BRACKET)*/
+ XK_decimalpoint = 0x0abd, /*(U+002E FULL STOP)*/
+ XK_rightanglebracket = 0x0abe, /*(U+27E9 MATHEMATICAL RIGHT ANGLE BRACKET)*/
+ XK_marker = 0x0abf,
+ XK_oneeighth = 0x0ac3, /* U+215B VULGAR FRACTION ONE EIGHTH */
+ XK_threeeighths = 0x0ac4, /* U+215C VULGAR FRACTION THREE EIGHTHS */
+ XK_fiveeighths = 0x0ac5, /* U+215D VULGAR FRACTION FIVE EIGHTHS */
+ XK_seveneighths = 0x0ac6, /* U+215E VULGAR FRACTION SEVEN EIGHTHS */
+ XK_trademark = 0x0ac9, /* U+2122 TRADE MARK SIGN */
+ XK_signaturemark = 0x0aca, /*(U+2613 SALTIRE)*/
+ XK_trademarkincircle = 0x0acb,
+ XK_leftopentriangle = 0x0acc, /*(U+25C1 WHITE LEFT-POINTING TRIANGLE)*/
+ XK_rightopentriangle = 0x0acd, /*(U+25B7 WHITE RIGHT-POINTING TRIANGLE)*/
+ XK_emopencircle = 0x0ace, /*(U+25CB WHITE CIRCLE)*/
+ XK_emopenrectangle = 0x0acf, /*(U+25AF WHITE VERTICAL RECTANGLE)*/
+ XK_leftsinglequotemark = 0x0ad0, /* U+2018 LEFT SINGLE QUOTATION MARK */
+ XK_rightsinglequotemark = 0x0ad1, /* U+2019 RIGHT SINGLE QUOTATION MARK */
+ XK_leftdoublequotemark = 0x0ad2, /* U+201C LEFT DOUBLE QUOTATION MARK */
+ XK_rightdoublequotemark = 0x0ad3, /* U+201D RIGHT DOUBLE QUOTATION MARK */
+ XK_prescription = 0x0ad4, /* U+211E PRESCRIPTION TAKE */
+ XK_minutes = 0x0ad6, /* U+2032 PRIME */
+ XK_seconds = 0x0ad7, /* U+2033 DOUBLE PRIME */
+ XK_latincross = 0x0ad9, /* U+271D LATIN CROSS */
+ XK_hexagram = 0x0ada,
+ XK_filledrectbullet = 0x0adb, /*(U+25AC BLACK RECTANGLE)*/
+ XK_filledlefttribullet = 0x0adc, /*(U+25C0 BLACK LEFT-POINTING TRIANGLE)*/
+ XK_filledrighttribullet = 0x0add, /*(U+25B6 BLACK RIGHT-POINTING TRIANGLE)*/
+ XK_emfilledcircle = 0x0ade, /*(U+25CF BLACK CIRCLE)*/
+ XK_emfilledrect = 0x0adf, /*(U+25AE BLACK VERTICAL RECTANGLE)*/
+ XK_enopencircbullet = 0x0ae0, /*(U+25E6 WHITE BULLET)*/
+ XK_enopensquarebullet = 0x0ae1, /*(U+25AB WHITE SMALL SQUARE)*/
+ XK_openrectbullet = 0x0ae2, /*(U+25AD WHITE RECTANGLE)*/
+ XK_opentribulletup = 0x0ae3, /*(U+25B3 WHITE UP-POINTING TRIANGLE)*/
+ XK_opentribulletdown = 0x0ae4, /*(U+25BD WHITE DOWN-POINTING TRIANGLE)*/
+ XK_openstar = 0x0ae5, /*(U+2606 WHITE STAR)*/
+ XK_enfilledcircbullet = 0x0ae6, /*(U+2022 BULLET)*/
+ XK_enfilledsqbullet = 0x0ae7, /*(U+25AA BLACK SMALL SQUARE)*/
+ XK_filledtribulletup = 0x0ae8, /*(U+25B2 BLACK UP-POINTING TRIANGLE)*/
+ XK_filledtribulletdown = 0x0ae9, /*(U+25BC BLACK DOWN-POINTING TRIANGLE)*/
+ XK_leftpointer = 0x0aea, /*(U+261C WHITE LEFT POINTING INDEX)*/
+ XK_rightpointer = 0x0aeb, /*(U+261E WHITE RIGHT POINTING INDEX)*/
+ XK_club = 0x0aec, /* U+2663 BLACK CLUB SUIT */
+ XK_diamond = 0x0aed, /* U+2666 BLACK DIAMOND SUIT */
+ XK_heart = 0x0aee, /* U+2665 BLACK HEART SUIT */
+ XK_maltesecross = 0x0af0, /* U+2720 MALTESE CROSS */
+ XK_dagger = 0x0af1, /* U+2020 DAGGER */
+ XK_doubledagger = 0x0af2, /* U+2021 DOUBLE DAGGER */
+ XK_checkmark = 0x0af3, /* U+2713 CHECK MARK */
+ XK_ballotcross = 0x0af4, /* U+2717 BALLOT X */
+ XK_musicalsharp = 0x0af5, /* U+266F MUSIC SHARP SIGN */
+ XK_musicalflat = 0x0af6, /* U+266D MUSIC FLAT SIGN */
+ XK_malesymbol = 0x0af7, /* U+2642 MALE SIGN */
+ XK_femalesymbol = 0x0af8, /* U+2640 FEMALE SIGN */
+ XK_telephone = 0x0af9, /* U+260E BLACK TELEPHONE */
+ XK_telephonerecorder = 0x0afa, /* U+2315 TELEPHONE RECORDER */
+ XK_phonographcopyright = 0x0afb, /* U+2117 SOUND RECORDING COPYRIGHT */
+ XK_caret = 0x0afc, /* U+2038 CARET */
+ XK_singlelowquotemark = 0x0afd, /* U+201A SINGLE LOW-9 QUOTATION MARK */
+ XK_doublelowquotemark = 0x0afe, /* U+201E DOUBLE LOW-9 QUOTATION MARK */
+ XK_cursor = 0x0aff,
+ XK_leftcaret = 0x0ba3, /*(U+003C LESS-THAN SIGN)*/
+ XK_rightcaret = 0x0ba6, /*(U+003E GREATER-THAN SIGN)*/
+ XK_downcaret = 0x0ba8, /*(U+2228 LOGICAL OR)*/
+ XK_upcaret = 0x0ba9, /*(U+2227 LOGICAL AND)*/
+ XK_overbar = 0x0bc0, /*(U+00AF MACRON)*/
+ XK_downtack = 0x0bc2, /* U+22A5 UP TACK */
+ XK_upshoe = 0x0bc3, /*(U+2229 INTERSECTION)*/
+ XK_downstile = 0x0bc4, /* U+230A LEFT FLOOR */
+ XK_underbar = 0x0bc6, /*(U+005F LOW LINE)*/
+ XK_jot = 0x0bca, /* U+2218 RING OPERATOR */
+ XK_quad = 0x0bcc, /* U+2395 APL FUNCTIONAL SYMBOL QUAD */
+ XK_uptack = 0x0bce, /* U+22A4 DOWN TACK */
+ XK_circle = 0x0bcf, /* U+25CB WHITE CIRCLE */
+ XK_upstile = 0x0bd3, /* U+2308 LEFT CEILING */
+ XK_downshoe = 0x0bd6, /*(U+222A UNION)*/
+ XK_rightshoe = 0x0bd8, /*(U+2283 SUPERSET OF)*/
+ XK_leftshoe = 0x0bda, /*(U+2282 SUBSET OF)*/
+ XK_lefttack = 0x0bdc, /* U+22A2 RIGHT TACK */
+ XK_righttack = 0x0bfc, /* U+22A3 LEFT TACK */
+ XK_hebrew_doublelowline = 0x0cdf, /* U+2017 DOUBLE LOW LINE */
+ XK_hebrew_aleph = 0x0ce0, /* U+05D0 HEBREW LETTER ALEF */
+ XK_hebrew_bet = 0x0ce1, /* U+05D1 HEBREW LETTER BET */
+ XK_hebrew_beth = 0x0ce1, /* deprecated */
+ XK_hebrew_gimel = 0x0ce2, /* U+05D2 HEBREW LETTER GIMEL */
+ XK_hebrew_gimmel = 0x0ce2, /* deprecated */
+ XK_hebrew_dalet = 0x0ce3, /* U+05D3 HEBREW LETTER DALET */
+ XK_hebrew_daleth = 0x0ce3, /* deprecated */
+ XK_hebrew_he = 0x0ce4, /* U+05D4 HEBREW LETTER HE */
+ XK_hebrew_waw = 0x0ce5, /* U+05D5 HEBREW LETTER VAV */
+ XK_hebrew_zain = 0x0ce6, /* U+05D6 HEBREW LETTER ZAYIN */
+ XK_hebrew_zayin = 0x0ce6, /* deprecated */
+ XK_hebrew_chet = 0x0ce7, /* U+05D7 HEBREW LETTER HET */
+ XK_hebrew_het = 0x0ce7, /* deprecated */
+ XK_hebrew_tet = 0x0ce8, /* U+05D8 HEBREW LETTER TET */
+ XK_hebrew_teth = 0x0ce8, /* deprecated */
+ XK_hebrew_yod = 0x0ce9, /* U+05D9 HEBREW LETTER YOD */
+ XK_hebrew_finalkaph = 0x0cea, /* U+05DA HEBREW LETTER FINAL KAF */
+ XK_hebrew_kaph = 0x0ceb, /* U+05DB HEBREW LETTER KAF */
+ XK_hebrew_lamed = 0x0cec, /* U+05DC HEBREW LETTER LAMED */
+ XK_hebrew_finalmem = 0x0ced, /* U+05DD HEBREW LETTER FINAL MEM */
+ XK_hebrew_mem = 0x0cee, /* U+05DE HEBREW LETTER MEM */
+ XK_hebrew_finalnun = 0x0cef, /* U+05DF HEBREW LETTER FINAL NUN */
+ XK_hebrew_nun = 0x0cf0, /* U+05E0 HEBREW LETTER NUN */
+ XK_hebrew_samech = 0x0cf1, /* U+05E1 HEBREW LETTER SAMEKH */
+ XK_hebrew_samekh = 0x0cf1, /* deprecated */
+ XK_hebrew_ayin = 0x0cf2, /* U+05E2 HEBREW LETTER AYIN */
+ XK_hebrew_finalpe = 0x0cf3, /* U+05E3 HEBREW LETTER FINAL PE */
+ XK_hebrew_pe = 0x0cf4, /* U+05E4 HEBREW LETTER PE */
+ XK_hebrew_finalzade = 0x0cf5, /* U+05E5 HEBREW LETTER FINAL TSADI */
+ XK_hebrew_finalzadi = 0x0cf5, /* deprecated */
+ XK_hebrew_zade = 0x0cf6, /* U+05E6 HEBREW LETTER TSADI */
+ XK_hebrew_zadi = 0x0cf6, /* deprecated */
+ XK_hebrew_qoph = 0x0cf7, /* U+05E7 HEBREW LETTER QOF */
+ XK_hebrew_kuf = 0x0cf7, /* deprecated */
+ XK_hebrew_resh = 0x0cf8, /* U+05E8 HEBREW LETTER RESH */
+ XK_hebrew_shin = 0x0cf9, /* U+05E9 HEBREW LETTER SHIN */
+ XK_hebrew_taw = 0x0cfa, /* U+05EA HEBREW LETTER TAV */
+ XK_hebrew_taf = 0x0cfa, /* deprecated */
+ XK_Hebrew_switch = 0xff7e, /* Alias for mode_switch */
+ XK_Thai_kokai = 0x0da1, /* U+0E01 THAI CHARACTER KO KAI */
+ XK_Thai_khokhai = 0x0da2, /* U+0E02 THAI CHARACTER KHO KHAI */
+ XK_Thai_khokhuat = 0x0da3, /* U+0E03 THAI CHARACTER KHO KHUAT */
+ XK_Thai_khokhwai = 0x0da4, /* U+0E04 THAI CHARACTER KHO KHWAI */
+ XK_Thai_khokhon = 0x0da5, /* U+0E05 THAI CHARACTER KHO KHON */
+ XK_Thai_khorakhang = 0x0da6, /* U+0E06 THAI CHARACTER KHO RAKHANG */
+ XK_Thai_ngongu = 0x0da7, /* U+0E07 THAI CHARACTER NGO NGU */
+ XK_Thai_chochan = 0x0da8, /* U+0E08 THAI CHARACTER CHO CHAN */
+ XK_Thai_choching = 0x0da9, /* U+0E09 THAI CHARACTER CHO CHING */
+ XK_Thai_chochang = 0x0daa, /* U+0E0A THAI CHARACTER CHO CHANG */
+ XK_Thai_soso = 0x0dab, /* U+0E0B THAI CHARACTER SO SO */
+ XK_Thai_chochoe = 0x0dac, /* U+0E0C THAI CHARACTER CHO CHOE */
+ XK_Thai_yoying = 0x0dad, /* U+0E0D THAI CHARACTER YO YING */
+ XK_Thai_dochada = 0x0dae, /* U+0E0E THAI CHARACTER DO CHADA */
+ XK_Thai_topatak = 0x0daf, /* U+0E0F THAI CHARACTER TO PATAK */
+ XK_Thai_thothan = 0x0db0, /* U+0E10 THAI CHARACTER THO THAN */
+ XK_Thai_thonangmontho = 0x0db1, /* U+0E11 THAI CHARACTER THO NANGMONTHO */
+ XK_Thai_thophuthao = 0x0db2, /* U+0E12 THAI CHARACTER THO PHUTHAO */
+ XK_Thai_nonen = 0x0db3, /* U+0E13 THAI CHARACTER NO NEN */
+ XK_Thai_dodek = 0x0db4, /* U+0E14 THAI CHARACTER DO DEK */
+ XK_Thai_totao = 0x0db5, /* U+0E15 THAI CHARACTER TO TAO */
+ XK_Thai_thothung = 0x0db6, /* U+0E16 THAI CHARACTER THO THUNG */
+ XK_Thai_thothahan = 0x0db7, /* U+0E17 THAI CHARACTER THO THAHAN */
+ XK_Thai_thothong = 0x0db8, /* U+0E18 THAI CHARACTER THO THONG */
+ XK_Thai_nonu = 0x0db9, /* U+0E19 THAI CHARACTER NO NU */
+ XK_Thai_bobaimai = 0x0dba, /* U+0E1A THAI CHARACTER BO BAIMAI */
+ XK_Thai_popla = 0x0dbb, /* U+0E1B THAI CHARACTER PO PLA */
+ XK_Thai_phophung = 0x0dbc, /* U+0E1C THAI CHARACTER PHO PHUNG */
+ XK_Thai_fofa = 0x0dbd, /* U+0E1D THAI CHARACTER FO FA */
+ XK_Thai_phophan = 0x0dbe, /* U+0E1E THAI CHARACTER PHO PHAN */
+ XK_Thai_fofan = 0x0dbf, /* U+0E1F THAI CHARACTER FO FAN */
+ XK_Thai_phosamphao = 0x0dc0, /* U+0E20 THAI CHARACTER PHO SAMPHAO */
+ XK_Thai_moma = 0x0dc1, /* U+0E21 THAI CHARACTER MO MA */
+ XK_Thai_yoyak = 0x0dc2, /* U+0E22 THAI CHARACTER YO YAK */
+ XK_Thai_rorua = 0x0dc3, /* U+0E23 THAI CHARACTER RO RUA */
+ XK_Thai_ru = 0x0dc4, /* U+0E24 THAI CHARACTER RU */
+ XK_Thai_loling = 0x0dc5, /* U+0E25 THAI CHARACTER LO LING */
+ XK_Thai_lu = 0x0dc6, /* U+0E26 THAI CHARACTER LU */
+ XK_Thai_wowaen = 0x0dc7, /* U+0E27 THAI CHARACTER WO WAEN */
+ XK_Thai_sosala = 0x0dc8, /* U+0E28 THAI CHARACTER SO SALA */
+ XK_Thai_sorusi = 0x0dc9, /* U+0E29 THAI CHARACTER SO RUSI */
+ XK_Thai_sosua = 0x0dca, /* U+0E2A THAI CHARACTER SO SUA */
+ XK_Thai_hohip = 0x0dcb, /* U+0E2B THAI CHARACTER HO HIP */
+ XK_Thai_lochula = 0x0dcc, /* U+0E2C THAI CHARACTER LO CHULA */
+ XK_Thai_oang = 0x0dcd, /* U+0E2D THAI CHARACTER O ANG */
+ XK_Thai_honokhuk = 0x0dce, /* U+0E2E THAI CHARACTER HO NOKHUK */
+ XK_Thai_paiyannoi = 0x0dcf, /* U+0E2F THAI CHARACTER PAIYANNOI */
+ XK_Thai_saraa = 0x0dd0, /* U+0E30 THAI CHARACTER SARA A */
+ XK_Thai_maihanakat = 0x0dd1, /* U+0E31 THAI CHARACTER MAI HAN-AKAT */
+ XK_Thai_saraaa = 0x0dd2, /* U+0E32 THAI CHARACTER SARA AA */
+ XK_Thai_saraam = 0x0dd3, /* U+0E33 THAI CHARACTER SARA AM */
+ XK_Thai_sarai = 0x0dd4, /* U+0E34 THAI CHARACTER SARA I */
+ XK_Thai_saraii = 0x0dd5, /* U+0E35 THAI CHARACTER SARA II */
+ XK_Thai_saraue = 0x0dd6, /* U+0E36 THAI CHARACTER SARA UE */
+ XK_Thai_sarauee = 0x0dd7, /* U+0E37 THAI CHARACTER SARA UEE */
+ XK_Thai_sarau = 0x0dd8, /* U+0E38 THAI CHARACTER SARA U */
+ XK_Thai_sarauu = 0x0dd9, /* U+0E39 THAI CHARACTER SARA UU */
+ XK_Thai_phinthu = 0x0dda, /* U+0E3A THAI CHARACTER PHINTHU */
+ XK_Thai_maihanakat_maitho = 0x0dde,
+ XK_Thai_baht = 0x0ddf, /* U+0E3F THAI CURRENCY SYMBOL BAHT */
+ XK_Thai_sarae = 0x0de0, /* U+0E40 THAI CHARACTER SARA E */
+ XK_Thai_saraae = 0x0de1, /* U+0E41 THAI CHARACTER SARA AE */
+ XK_Thai_sarao = 0x0de2, /* U+0E42 THAI CHARACTER SARA O */
+ XK_Thai_saraaimaimuan = 0x0de3, /* U+0E43 THAI CHARACTER SARA AI MAIMUAN */
+ XK_Thai_saraaimaimalai = 0x0de4, /* U+0E44 THAI CHARACTER SARA AI MAIMALAI */
+ XK_Thai_lakkhangyao = 0x0de5, /* U+0E45 THAI CHARACTER LAKKHANGYAO */
+ XK_Thai_maiyamok = 0x0de6, /* U+0E46 THAI CHARACTER MAIYAMOK */
+ XK_Thai_maitaikhu = 0x0de7, /* U+0E47 THAI CHARACTER MAITAIKHU */
+ XK_Thai_maiek = 0x0de8, /* U+0E48 THAI CHARACTER MAI EK */
+ XK_Thai_maitho = 0x0de9, /* U+0E49 THAI CHARACTER MAI THO */
+ XK_Thai_maitri = 0x0dea, /* U+0E4A THAI CHARACTER MAI TRI */
+ XK_Thai_maichattawa = 0x0deb, /* U+0E4B THAI CHARACTER MAI CHATTAWA */
+ XK_Thai_thanthakhat = 0x0dec, /* U+0E4C THAI CHARACTER THANTHAKHAT */
+ XK_Thai_nikhahit = 0x0ded, /* U+0E4D THAI CHARACTER NIKHAHIT */
+ XK_Thai_leksun = 0x0df0, /* U+0E50 THAI DIGIT ZERO */
+ XK_Thai_leknung = 0x0df1, /* U+0E51 THAI DIGIT ONE */
+ XK_Thai_leksong = 0x0df2, /* U+0E52 THAI DIGIT TWO */
+ XK_Thai_leksam = 0x0df3, /* U+0E53 THAI DIGIT THREE */
+ XK_Thai_leksi = 0x0df4, /* U+0E54 THAI DIGIT FOUR */
+ XK_Thai_lekha = 0x0df5, /* U+0E55 THAI DIGIT FIVE */
+ XK_Thai_lekhok = 0x0df6, /* U+0E56 THAI DIGIT SIX */
+ XK_Thai_lekchet = 0x0df7, /* U+0E57 THAI DIGIT SEVEN */
+ XK_Thai_lekpaet = 0x0df8, /* U+0E58 THAI DIGIT EIGHT */
+ XK_Thai_lekkao = 0x0df9, /* U+0E59 THAI DIGIT NINE */
+ XK_Hangul = 0xff31, /* Hangul start/stop(toggle) */
+ XK_Hangul_Start = 0xff32, /* Hangul start */
+ XK_Hangul_End = 0xff33, /* Hangul end, English start */
+ XK_Hangul_Hanja = 0xff34, /* Start Hangul->Hanja Conversion */
+ XK_Hangul_Jamo = 0xff35, /* Hangul Jamo mode */
+ XK_Hangul_Romaja = 0xff36, /* Hangul Romaja mode */
+ XK_Hangul_Codeinput = 0xff37, /* Hangul code input mode */
+ XK_Hangul_Jeonja = 0xff38, /* Jeonja mode */
+ XK_Hangul_Banja = 0xff39, /* Banja mode */
+ XK_Hangul_PreHanja = 0xff3a, /* Pre Hanja conversion */
+ XK_Hangul_PostHanja = 0xff3b, /* Post Hanja conversion */
+ XK_Hangul_SingleCandidate = 0xff3c, /* Single candidate */
+ XK_Hangul_MultipleCandidate = 0xff3d, /* Multiple candidate */
+ XK_Hangul_PreviousCandidate = 0xff3e, /* Previous candidate */
+ XK_Hangul_Special = 0xff3f, /* Special symbols */
+ XK_Hangul_switch = 0xff7e, /* Alias for mode_switch */
+ XK_Hangul_Kiyeog = 0x0ea1,
+ XK_Hangul_SsangKiyeog = 0x0ea2,
+ XK_Hangul_KiyeogSios = 0x0ea3,
+ XK_Hangul_Nieun = 0x0ea4,
+ XK_Hangul_NieunJieuj = 0x0ea5,
+ XK_Hangul_NieunHieuh = 0x0ea6,
+ XK_Hangul_Dikeud = 0x0ea7,
+ XK_Hangul_SsangDikeud = 0x0ea8,
+ XK_Hangul_Rieul = 0x0ea9,
+ XK_Hangul_RieulKiyeog = 0x0eaa,
+ XK_Hangul_RieulMieum = 0x0eab,
+ XK_Hangul_RieulPieub = 0x0eac,
+ XK_Hangul_RieulSios = 0x0ead,
+ XK_Hangul_RieulTieut = 0x0eae,
+ XK_Hangul_RieulPhieuf = 0x0eaf,
+ XK_Hangul_RieulHieuh = 0x0eb0,
+ XK_Hangul_Mieum = 0x0eb1,
+ XK_Hangul_Pieub = 0x0eb2,
+ XK_Hangul_SsangPieub = 0x0eb3,
+ XK_Hangul_PieubSios = 0x0eb4,
+ XK_Hangul_Sios = 0x0eb5,
+ XK_Hangul_SsangSios = 0x0eb6,
+ XK_Hangul_Ieung = 0x0eb7,
+ XK_Hangul_Jieuj = 0x0eb8,
+ XK_Hangul_SsangJieuj = 0x0eb9,
+ XK_Hangul_Cieuc = 0x0eba,
+ XK_Hangul_Khieuq = 0x0ebb,
+ XK_Hangul_Tieut = 0x0ebc,
+ XK_Hangul_Phieuf = 0x0ebd,
+ XK_Hangul_Hieuh = 0x0ebe,
+ XK_Hangul_A = 0x0ebf,
+ XK_Hangul_AE = 0x0ec0,
+ XK_Hangul_YA = 0x0ec1,
+ XK_Hangul_YAE = 0x0ec2,
+ XK_Hangul_EO = 0x0ec3,
+ XK_Hangul_E = 0x0ec4,
+ XK_Hangul_YEO = 0x0ec5,
+ XK_Hangul_YE = 0x0ec6,
+ XK_Hangul_O = 0x0ec7,
+ XK_Hangul_WA = 0x0ec8,
+ XK_Hangul_WAE = 0x0ec9,
+ XK_Hangul_OE = 0x0eca,
+ XK_Hangul_YO = 0x0ecb,
+ XK_Hangul_U = 0x0ecc,
+ XK_Hangul_WEO = 0x0ecd,
+ XK_Hangul_WE = 0x0ece,
+ XK_Hangul_WI = 0x0ecf,
+ XK_Hangul_YU = 0x0ed0,
+ XK_Hangul_EU = 0x0ed1,
+ XK_Hangul_YI = 0x0ed2,
+ XK_Hangul_I = 0x0ed3,
+ XK_Hangul_J_Kiyeog = 0x0ed4,
+ XK_Hangul_J_SsangKiyeog = 0x0ed5,
+ XK_Hangul_J_KiyeogSios = 0x0ed6,
+ XK_Hangul_J_Nieun = 0x0ed7,
+ XK_Hangul_J_NieunJieuj = 0x0ed8,
+ XK_Hangul_J_NieunHieuh = 0x0ed9,
+ XK_Hangul_J_Dikeud = 0x0eda,
+ XK_Hangul_J_Rieul = 0x0edb,
+ XK_Hangul_J_RieulKiyeog = 0x0edc,
+ XK_Hangul_J_RieulMieum = 0x0edd,
+ XK_Hangul_J_RieulPieub = 0x0ede,
+ XK_Hangul_J_RieulSios = 0x0edf,
+ XK_Hangul_J_RieulTieut = 0x0ee0,
+ XK_Hangul_J_RieulPhieuf = 0x0ee1,
+ XK_Hangul_J_RieulHieuh = 0x0ee2,
+ XK_Hangul_J_Mieum = 0x0ee3,
+ XK_Hangul_J_Pieub = 0x0ee4,
+ XK_Hangul_J_PieubSios = 0x0ee5,
+ XK_Hangul_J_Sios = 0x0ee6,
+ XK_Hangul_J_SsangSios = 0x0ee7,
+ XK_Hangul_J_Ieung = 0x0ee8,
+ XK_Hangul_J_Jieuj = 0x0ee9,
+ XK_Hangul_J_Cieuc = 0x0eea,
+ XK_Hangul_J_Khieuq = 0x0eeb,
+ XK_Hangul_J_Tieut = 0x0eec,
+ XK_Hangul_J_Phieuf = 0x0eed,
+ XK_Hangul_J_Hieuh = 0x0eee,
+ XK_Hangul_RieulYeorinHieuh = 0x0eef,
+ XK_Hangul_SunkyeongeumMieum = 0x0ef0,
+ XK_Hangul_SunkyeongeumPieub = 0x0ef1,
+ XK_Hangul_PanSios = 0x0ef2,
+ XK_Hangul_KkogjiDalrinIeung = 0x0ef3,
+ XK_Hangul_SunkyeongeumPhieuf = 0x0ef4,
+ XK_Hangul_YeorinHieuh = 0x0ef5,
+ XK_Hangul_AraeA = 0x0ef6,
+ XK_Hangul_AraeAE = 0x0ef7,
+ XK_Hangul_J_PanSios = 0x0ef8,
+ XK_Hangul_J_KkogjiDalrinIeung = 0x0ef9,
+ XK_Hangul_J_YeorinHieuh = 0x0efa,
+ XK_Korean_Won = 0x0eff, /*(U+20A9 WON SIGN)*/
+ XK_Armenian_ligature_ew = 0x1000587, /* U+0587 ARMENIAN SMALL LIGATURE ECH YIWN */
+ XK_Armenian_full_stop = 0x1000589, /* U+0589 ARMENIAN FULL STOP */
+ XK_Armenian_verjaket = 0x1000589, /* U+0589 ARMENIAN FULL STOP */
+ XK_Armenian_separation_mark = 0x100055d, /* U+055D ARMENIAN COMMA */
+ XK_Armenian_but = 0x100055d, /* U+055D ARMENIAN COMMA */
+ XK_Armenian_hyphen = 0x100058a, /* U+058A ARMENIAN HYPHEN */
+ XK_Armenian_yentamna = 0x100058a, /* U+058A ARMENIAN HYPHEN */
+ XK_Armenian_exclam = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */
+ XK_Armenian_amanak = 0x100055c, /* U+055C ARMENIAN EXCLAMATION MARK */
+ XK_Armenian_accent = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */
+ XK_Armenian_shesht = 0x100055b, /* U+055B ARMENIAN EMPHASIS MARK */
+ XK_Armenian_question = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */
+ XK_Armenian_paruyk = 0x100055e, /* U+055E ARMENIAN QUESTION MARK */
+ XK_Armenian_AYB = 0x1000531, /* U+0531 ARMENIAN CAPITAL LETTER AYB */
+ XK_Armenian_ayb = 0x1000561, /* U+0561 ARMENIAN SMALL LETTER AYB */
+ XK_Armenian_BEN = 0x1000532, /* U+0532 ARMENIAN CAPITAL LETTER BEN */
+ XK_Armenian_ben = 0x1000562, /* U+0562 ARMENIAN SMALL LETTER BEN */
+ XK_Armenian_GIM = 0x1000533, /* U+0533 ARMENIAN CAPITAL LETTER GIM */
+ XK_Armenian_gim = 0x1000563, /* U+0563 ARMENIAN SMALL LETTER GIM */
+ XK_Armenian_DA = 0x1000534, /* U+0534 ARMENIAN CAPITAL LETTER DA */
+ XK_Armenian_da = 0x1000564, /* U+0564 ARMENIAN SMALL LETTER DA */
+ XK_Armenian_YECH = 0x1000535, /* U+0535 ARMENIAN CAPITAL LETTER ECH */
+ XK_Armenian_yech = 0x1000565, /* U+0565 ARMENIAN SMALL LETTER ECH */
+ XK_Armenian_ZA = 0x1000536, /* U+0536 ARMENIAN CAPITAL LETTER ZA */
+ XK_Armenian_za = 0x1000566, /* U+0566 ARMENIAN SMALL LETTER ZA */
+ XK_Armenian_E = 0x1000537, /* U+0537 ARMENIAN CAPITAL LETTER EH */
+ XK_Armenian_e = 0x1000567, /* U+0567 ARMENIAN SMALL LETTER EH */
+ XK_Armenian_AT = 0x1000538, /* U+0538 ARMENIAN CAPITAL LETTER ET */
+ XK_Armenian_at = 0x1000568, /* U+0568 ARMENIAN SMALL LETTER ET */
+ XK_Armenian_TO = 0x1000539, /* U+0539 ARMENIAN CAPITAL LETTER TO */
+ XK_Armenian_to = 0x1000569, /* U+0569 ARMENIAN SMALL LETTER TO */
+ XK_Armenian_ZHE = 0x100053a, /* U+053A ARMENIAN CAPITAL LETTER ZHE */
+ XK_Armenian_zhe = 0x100056a, /* U+056A ARMENIAN SMALL LETTER ZHE */
+ XK_Armenian_INI = 0x100053b, /* U+053B ARMENIAN CAPITAL LETTER INI */
+ XK_Armenian_ini = 0x100056b, /* U+056B ARMENIAN SMALL LETTER INI */
+ XK_Armenian_LYUN = 0x100053c, /* U+053C ARMENIAN CAPITAL LETTER LIWN */
+ XK_Armenian_lyun = 0x100056c, /* U+056C ARMENIAN SMALL LETTER LIWN */
+ XK_Armenian_KHE = 0x100053d, /* U+053D ARMENIAN CAPITAL LETTER XEH */
+ XK_Armenian_khe = 0x100056d, /* U+056D ARMENIAN SMALL LETTER XEH */
+ XK_Armenian_TSA = 0x100053e, /* U+053E ARMENIAN CAPITAL LETTER CA */
+ XK_Armenian_tsa = 0x100056e, /* U+056E ARMENIAN SMALL LETTER CA */
+ XK_Armenian_KEN = 0x100053f, /* U+053F ARMENIAN CAPITAL LETTER KEN */
+ XK_Armenian_ken = 0x100056f, /* U+056F ARMENIAN SMALL LETTER KEN */
+ XK_Armenian_HO = 0x1000540, /* U+0540 ARMENIAN CAPITAL LETTER HO */
+ XK_Armenian_ho = 0x1000570, /* U+0570 ARMENIAN SMALL LETTER HO */
+ XK_Armenian_DZA = 0x1000541, /* U+0541 ARMENIAN CAPITAL LETTER JA */
+ XK_Armenian_dza = 0x1000571, /* U+0571 ARMENIAN SMALL LETTER JA */
+ XK_Armenian_GHAT = 0x1000542, /* U+0542 ARMENIAN CAPITAL LETTER GHAD */
+ XK_Armenian_ghat = 0x1000572, /* U+0572 ARMENIAN SMALL LETTER GHAD */
+ XK_Armenian_TCHE = 0x1000543, /* U+0543 ARMENIAN CAPITAL LETTER CHEH */
+ XK_Armenian_tche = 0x1000573, /* U+0573 ARMENIAN SMALL LETTER CHEH */
+ XK_Armenian_MEN = 0x1000544, /* U+0544 ARMENIAN CAPITAL LETTER MEN */
+ XK_Armenian_men = 0x1000574, /* U+0574 ARMENIAN SMALL LETTER MEN */
+ XK_Armenian_HI = 0x1000545, /* U+0545 ARMENIAN CAPITAL LETTER YI */
+ XK_Armenian_hi = 0x1000575, /* U+0575 ARMENIAN SMALL LETTER YI */
+ XK_Armenian_NU = 0x1000546, /* U+0546 ARMENIAN CAPITAL LETTER NOW */
+ XK_Armenian_nu = 0x1000576, /* U+0576 ARMENIAN SMALL LETTER NOW */
+ XK_Armenian_SHA = 0x1000547, /* U+0547 ARMENIAN CAPITAL LETTER SHA */
+ XK_Armenian_sha = 0x1000577, /* U+0577 ARMENIAN SMALL LETTER SHA */
+ XK_Armenian_VO = 0x1000548, /* U+0548 ARMENIAN CAPITAL LETTER VO */
+ XK_Armenian_vo = 0x1000578, /* U+0578 ARMENIAN SMALL LETTER VO */
+ XK_Armenian_CHA = 0x1000549, /* U+0549 ARMENIAN CAPITAL LETTER CHA */
+ XK_Armenian_cha = 0x1000579, /* U+0579 ARMENIAN SMALL LETTER CHA */
+ XK_Armenian_PE = 0x100054a, /* U+054A ARMENIAN CAPITAL LETTER PEH */
+ XK_Armenian_pe = 0x100057a, /* U+057A ARMENIAN SMALL LETTER PEH */
+ XK_Armenian_JE = 0x100054b, /* U+054B ARMENIAN CAPITAL LETTER JHEH */
+ XK_Armenian_je = 0x100057b, /* U+057B ARMENIAN SMALL LETTER JHEH */
+ XK_Armenian_RA = 0x100054c, /* U+054C ARMENIAN CAPITAL LETTER RA */
+ XK_Armenian_ra = 0x100057c, /* U+057C ARMENIAN SMALL LETTER RA */
+ XK_Armenian_SE = 0x100054d, /* U+054D ARMENIAN CAPITAL LETTER SEH */
+ XK_Armenian_se = 0x100057d, /* U+057D ARMENIAN SMALL LETTER SEH */
+ XK_Armenian_VEV = 0x100054e, /* U+054E ARMENIAN CAPITAL LETTER VEW */
+ XK_Armenian_vev = 0x100057e, /* U+057E ARMENIAN SMALL LETTER VEW */
+ XK_Armenian_TYUN = 0x100054f, /* U+054F ARMENIAN CAPITAL LETTER TIWN */
+ XK_Armenian_tyun = 0x100057f, /* U+057F ARMENIAN SMALL LETTER TIWN */
+ XK_Armenian_RE = 0x1000550, /* U+0550 ARMENIAN CAPITAL LETTER REH */
+ XK_Armenian_re = 0x1000580, /* U+0580 ARMENIAN SMALL LETTER REH */
+ XK_Armenian_TSO = 0x1000551, /* U+0551 ARMENIAN CAPITAL LETTER CO */
+ XK_Armenian_tso = 0x1000581, /* U+0581 ARMENIAN SMALL LETTER CO */
+ XK_Armenian_VYUN = 0x1000552, /* U+0552 ARMENIAN CAPITAL LETTER YIWN */
+ XK_Armenian_vyun = 0x1000582, /* U+0582 ARMENIAN SMALL LETTER YIWN */
+ XK_Armenian_PYUR = 0x1000553, /* U+0553 ARMENIAN CAPITAL LETTER PIWR */
+ XK_Armenian_pyur = 0x1000583, /* U+0583 ARMENIAN SMALL LETTER PIWR */
+ XK_Armenian_KE = 0x1000554, /* U+0554 ARMENIAN CAPITAL LETTER KEH */
+ XK_Armenian_ke = 0x1000584, /* U+0584 ARMENIAN SMALL LETTER KEH */
+ XK_Armenian_O = 0x1000555, /* U+0555 ARMENIAN CAPITAL LETTER OH */
+ XK_Armenian_o = 0x1000585, /* U+0585 ARMENIAN SMALL LETTER OH */
+ XK_Armenian_FE = 0x1000556, /* U+0556 ARMENIAN CAPITAL LETTER FEH */
+ XK_Armenian_fe = 0x1000586, /* U+0586 ARMENIAN SMALL LETTER FEH */
+ XK_Armenian_apostrophe = 0x100055a, /* U+055A ARMENIAN APOSTROPHE */
+ XK_Georgian_an = 0x10010d0, /* U+10D0 GEORGIAN LETTER AN */
+ XK_Georgian_ban = 0x10010d1, /* U+10D1 GEORGIAN LETTER BAN */
+ XK_Georgian_gan = 0x10010d2, /* U+10D2 GEORGIAN LETTER GAN */
+ XK_Georgian_don = 0x10010d3, /* U+10D3 GEORGIAN LETTER DON */
+ XK_Georgian_en = 0x10010d4, /* U+10D4 GEORGIAN LETTER EN */
+ XK_Georgian_vin = 0x10010d5, /* U+10D5 GEORGIAN LETTER VIN */
+ XK_Georgian_zen = 0x10010d6, /* U+10D6 GEORGIAN LETTER ZEN */
+ XK_Georgian_tan = 0x10010d7, /* U+10D7 GEORGIAN LETTER TAN */
+ XK_Georgian_in = 0x10010d8, /* U+10D8 GEORGIAN LETTER IN */
+ XK_Georgian_kan = 0x10010d9, /* U+10D9 GEORGIAN LETTER KAN */
+ XK_Georgian_las = 0x10010da, /* U+10DA GEORGIAN LETTER LAS */
+ XK_Georgian_man = 0x10010db, /* U+10DB GEORGIAN LETTER MAN */
+ XK_Georgian_nar = 0x10010dc, /* U+10DC GEORGIAN LETTER NAR */
+ XK_Georgian_on = 0x10010dd, /* U+10DD GEORGIAN LETTER ON */
+ XK_Georgian_par = 0x10010de, /* U+10DE GEORGIAN LETTER PAR */
+ XK_Georgian_zhar = 0x10010df, /* U+10DF GEORGIAN LETTER ZHAR */
+ XK_Georgian_rae = 0x10010e0, /* U+10E0 GEORGIAN LETTER RAE */
+ XK_Georgian_san = 0x10010e1, /* U+10E1 GEORGIAN LETTER SAN */
+ XK_Georgian_tar = 0x10010e2, /* U+10E2 GEORGIAN LETTER TAR */
+ XK_Georgian_un = 0x10010e3, /* U+10E3 GEORGIAN LETTER UN */
+ XK_Georgian_phar = 0x10010e4, /* U+10E4 GEORGIAN LETTER PHAR */
+ XK_Georgian_khar = 0x10010e5, /* U+10E5 GEORGIAN LETTER KHAR */
+ XK_Georgian_ghan = 0x10010e6, /* U+10E6 GEORGIAN LETTER GHAN */
+ XK_Georgian_qar = 0x10010e7, /* U+10E7 GEORGIAN LETTER QAR */
+ XK_Georgian_shin = 0x10010e8, /* U+10E8 GEORGIAN LETTER SHIN */
+ XK_Georgian_chin = 0x10010e9, /* U+10E9 GEORGIAN LETTER CHIN */
+ XK_Georgian_can = 0x10010ea, /* U+10EA GEORGIAN LETTER CAN */
+ XK_Georgian_jil = 0x10010eb, /* U+10EB GEORGIAN LETTER JIL */
+ XK_Georgian_cil = 0x10010ec, /* U+10EC GEORGIAN LETTER CIL */
+ XK_Georgian_char = 0x10010ed, /* U+10ED GEORGIAN LETTER CHAR */
+ XK_Georgian_xan = 0x10010ee, /* U+10EE GEORGIAN LETTER XAN */
+ XK_Georgian_jhan = 0x10010ef, /* U+10EF GEORGIAN LETTER JHAN */
+ XK_Georgian_hae = 0x10010f0, /* U+10F0 GEORGIAN LETTER HAE */
+ XK_Georgian_he = 0x10010f1, /* U+10F1 GEORGIAN LETTER HE */
+ XK_Georgian_hie = 0x10010f2, /* U+10F2 GEORGIAN LETTER HIE */
+ XK_Georgian_we = 0x10010f3, /* U+10F3 GEORGIAN LETTER WE */
+ XK_Georgian_har = 0x10010f4, /* U+10F4 GEORGIAN LETTER HAR */
+ XK_Georgian_hoe = 0x10010f5, /* U+10F5 GEORGIAN LETTER HOE */
+ XK_Georgian_fi = 0x10010f6, /* U+10F6 GEORGIAN LETTER FI */
+ XK_Xabovedot = 0x1001e8a, /* U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE */
+ XK_Ibreve = 0x100012c, /* U+012C LATIN CAPITAL LETTER I WITH BREVE */
+ XK_Zstroke = 0x10001b5, /* U+01B5 LATIN CAPITAL LETTER Z WITH STROKE */
+ XK_Gcaron = 0x10001e6, /* U+01E6 LATIN CAPITAL LETTER G WITH CARON */
+ XK_Ocaron = 0x10001d1, /* U+01D2 LATIN CAPITAL LETTER O WITH CARON */
+ XK_Obarred = 0x100019f, /* U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE */
+ XK_xabovedot = 0x1001e8b, /* U+1E8B LATIN SMALL LETTER X WITH DOT ABOVE */
+ XK_ibreve = 0x100012d, /* U+012D LATIN SMALL LETTER I WITH BREVE */
+ XK_zstroke = 0x10001b6, /* U+01B6 LATIN SMALL LETTER Z WITH STROKE */
+ XK_gcaron = 0x10001e7, /* U+01E7 LATIN SMALL LETTER G WITH CARON */
+ XK_ocaron = 0x10001d2, /* U+01D2 LATIN SMALL LETTER O WITH CARON */
+ XK_obarred = 0x1000275, /* U+0275 LATIN SMALL LETTER BARRED O */
+ XK_SCHWA = 0x100018f, /* U+018F LATIN CAPITAL LETTER SCHWA */
+ XK_schwa = 0x1000259, /* U+0259 LATIN SMALL LETTER SCHWA */
+ XK_Lbelowdot = 0x1001e36, /* U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW */
+ XK_lbelowdot = 0x1001e37, /* U+1E37 LATIN SMALL LETTER L WITH DOT BELOW */
+ XK_Abelowdot = 0x1001ea0, /* U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW */
+ XK_abelowdot = 0x1001ea1, /* U+1EA1 LATIN SMALL LETTER A WITH DOT BELOW */
+ XK_Ahook = 0x1001ea2, /* U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE */
+ XK_ahook = 0x1001ea3, /* U+1EA3 LATIN SMALL LETTER A WITH HOOK ABOVE */
+ XK_Acircumflexacute = 0x1001ea4, /* U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */
+ XK_acircumflexacute = 0x1001ea5, /* U+1EA5 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */
+ XK_Acircumflexgrave = 0x1001ea6, /* U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */
+ XK_acircumflexgrave = 0x1001ea7, /* U+1EA7 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */
+ XK_Acircumflexhook = 0x1001ea8, /* U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_acircumflexhook = 0x1001ea9, /* U+1EA9 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_Acircumflextilde = 0x1001eaa, /* U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */
+ XK_acircumflextilde = 0x1001eab, /* U+1EAB LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */
+ XK_Acircumflexbelowdot = 0x1001eac, /* U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
+ XK_acircumflexbelowdot = 0x1001ead, /* U+1EAD LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */
+ XK_Abreveacute = 0x1001eae, /* U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */
+ XK_abreveacute = 0x1001eaf, /* U+1EAF LATIN SMALL LETTER A WITH BREVE AND ACUTE */
+ XK_Abrevegrave = 0x1001eb0, /* U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */
+ XK_abrevegrave = 0x1001eb1, /* U+1EB1 LATIN SMALL LETTER A WITH BREVE AND GRAVE */
+ XK_Abrevehook = 0x1001eb2, /* U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */
+ XK_abrevehook = 0x1001eb3, /* U+1EB3 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */
+ XK_Abrevetilde = 0x1001eb4, /* U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE */
+ XK_abrevetilde = 0x1001eb5, /* U+1EB5 LATIN SMALL LETTER A WITH BREVE AND TILDE */
+ XK_Abrevebelowdot = 0x1001eb6, /* U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */
+ XK_abrevebelowdot = 0x1001eb7, /* U+1EB7 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */
+ XK_Ebelowdot = 0x1001eb8, /* U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW */
+ XK_ebelowdot = 0x1001eb9, /* U+1EB9 LATIN SMALL LETTER E WITH DOT BELOW */
+ XK_Ehook = 0x1001eba, /* U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE */
+ XK_ehook = 0x1001ebb, /* U+1EBB LATIN SMALL LETTER E WITH HOOK ABOVE */
+ XK_Etilde = 0x1001ebc, /* U+1EBC LATIN CAPITAL LETTER E WITH TILDE */
+ XK_etilde = 0x1001ebd, /* U+1EBD LATIN SMALL LETTER E WITH TILDE */
+ XK_Ecircumflexacute = 0x1001ebe, /* U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */
+ XK_ecircumflexacute = 0x1001ebf, /* U+1EBF LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */
+ XK_Ecircumflexgrave = 0x1001ec0, /* U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */
+ XK_ecircumflexgrave = 0x1001ec1, /* U+1EC1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */
+ XK_Ecircumflexhook = 0x1001ec2, /* U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_ecircumflexhook = 0x1001ec3, /* U+1EC3 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_Ecircumflextilde = 0x1001ec4, /* U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */
+ XK_ecircumflextilde = 0x1001ec5, /* U+1EC5 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */
+ XK_Ecircumflexbelowdot = 0x1001ec6, /* U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
+ XK_ecircumflexbelowdot = 0x1001ec7, /* U+1EC7 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */
+ XK_Ihook = 0x1001ec8, /* U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE */
+ XK_ihook = 0x1001ec9, /* U+1EC9 LATIN SMALL LETTER I WITH HOOK ABOVE */
+ XK_Ibelowdot = 0x1001eca, /* U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW */
+ XK_ibelowdot = 0x1001ecb, /* U+1ECB LATIN SMALL LETTER I WITH DOT BELOW */
+ XK_Obelowdot = 0x1001ecc, /* U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW */
+ XK_obelowdot = 0x1001ecd, /* U+1ECD LATIN SMALL LETTER O WITH DOT BELOW */
+ XK_Ohook = 0x1001ece, /* U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE */
+ XK_ohook = 0x1001ecf, /* U+1ECF LATIN SMALL LETTER O WITH HOOK ABOVE */
+ XK_Ocircumflexacute = 0x1001ed0, /* U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */
+ XK_ocircumflexacute = 0x1001ed1, /* U+1ED1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */
+ XK_Ocircumflexgrave = 0x1001ed2, /* U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */
+ XK_ocircumflexgrave = 0x1001ed3, /* U+1ED3 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */
+ XK_Ocircumflexhook = 0x1001ed4, /* U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_ocircumflexhook = 0x1001ed5, /* U+1ED5 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */
+ XK_Ocircumflextilde = 0x1001ed6, /* U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */
+ XK_ocircumflextilde = 0x1001ed7, /* U+1ED7 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */
+ XK_Ocircumflexbelowdot = 0x1001ed8, /* U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
+ XK_ocircumflexbelowdot = 0x1001ed9, /* U+1ED9 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */
+ XK_Ohornacute = 0x1001eda, /* U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE */
+ XK_ohornacute = 0x1001edb, /* U+1EDB LATIN SMALL LETTER O WITH HORN AND ACUTE */
+ XK_Ohorngrave = 0x1001edc, /* U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE */
+ XK_ohorngrave = 0x1001edd, /* U+1EDD LATIN SMALL LETTER O WITH HORN AND GRAVE */
+ XK_Ohornhook = 0x1001ede, /* U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */
+ XK_ohornhook = 0x1001edf, /* U+1EDF LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */
+ XK_Ohorntilde = 0x1001ee0, /* U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE */
+ XK_ohorntilde = 0x1001ee1, /* U+1EE1 LATIN SMALL LETTER O WITH HORN AND TILDE */
+ XK_Ohornbelowdot = 0x1001ee2, /* U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */
+ XK_ohornbelowdot = 0x1001ee3, /* U+1EE3 LATIN SMALL LETTER O WITH HORN AND DOT BELOW */
+ XK_Ubelowdot = 0x1001ee4, /* U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW */
+ XK_ubelowdot = 0x1001ee5, /* U+1EE5 LATIN SMALL LETTER U WITH DOT BELOW */
+ XK_Uhook = 0x1001ee6, /* U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE */
+ XK_uhook = 0x1001ee7, /* U+1EE7 LATIN SMALL LETTER U WITH HOOK ABOVE */
+ XK_Uhornacute = 0x1001ee8, /* U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE */
+ XK_uhornacute = 0x1001ee9, /* U+1EE9 LATIN SMALL LETTER U WITH HORN AND ACUTE */
+ XK_Uhorngrave = 0x1001eea, /* U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE */
+ XK_uhorngrave = 0x1001eeb, /* U+1EEB LATIN SMALL LETTER U WITH HORN AND GRAVE */
+ XK_Uhornhook = 0x1001eec, /* U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */
+ XK_uhornhook = 0x1001eed, /* U+1EED LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */
+ XK_Uhorntilde = 0x1001eee, /* U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE */
+ XK_uhorntilde = 0x1001eef, /* U+1EEF LATIN SMALL LETTER U WITH HORN AND TILDE */
+ XK_Uhornbelowdot = 0x1001ef0, /* U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */
+ XK_uhornbelowdot = 0x1001ef1, /* U+1EF1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW */
+ XK_Ybelowdot = 0x1001ef4, /* U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW */
+ XK_ybelowdot = 0x1001ef5, /* U+1EF5 LATIN SMALL LETTER Y WITH DOT BELOW */
+ XK_Yhook = 0x1001ef6, /* U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE */
+ XK_yhook = 0x1001ef7, /* U+1EF7 LATIN SMALL LETTER Y WITH HOOK ABOVE */
+ XK_Ytilde = 0x1001ef8, /* U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE */
+ XK_ytilde = 0x1001ef9, /* U+1EF9 LATIN SMALL LETTER Y WITH TILDE */
+ XK_Ohorn = 0x10001a0, /* U+01A0 LATIN CAPITAL LETTER O WITH HORN */
+ XK_ohorn = 0x10001a1, /* U+01A1 LATIN SMALL LETTER O WITH HORN */
+ XK_Uhorn = 0x10001af, /* U+01AF LATIN CAPITAL LETTER U WITH HORN */
+ XK_uhorn = 0x10001b0, /* U+01B0 LATIN SMALL LETTER U WITH HORN */
+ XK_EcuSign = 0x10020a0, /* U+20A0 EURO-CURRENCY SIGN */
+ XK_ColonSign = 0x10020a1, /* U+20A1 COLON SIGN */
+ XK_CruzeiroSign = 0x10020a2, /* U+20A2 CRUZEIRO SIGN */
+ XK_FFrancSign = 0x10020a3, /* U+20A3 FRENCH FRANC SIGN */
+ XK_LiraSign = 0x10020a4, /* U+20A4 LIRA SIGN */
+ XK_MillSign = 0x10020a5, /* U+20A5 MILL SIGN */
+ XK_NairaSign = 0x10020a6, /* U+20A6 NAIRA SIGN */
+ XK_PesetaSign = 0x10020a7, /* U+20A7 PESETA SIGN */
+ XK_RupeeSign = 0x10020a8, /* U+20A8 RUPEE SIGN */
+ XK_WonSign = 0x10020a9, /* U+20A9 WON SIGN */
+ XK_NewSheqelSign = 0x10020aa, /* U+20AA NEW SHEQEL SIGN */
+ XK_DongSign = 0x10020ab, /* U+20AB DONG SIGN */
+ XK_EuroSign = 0x20ac, /* U+20AC EURO SIGN */
}
diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin
index b5365e73d..2d35ab179 100644
--- a/vendor/x11/xlib/xlib_procs.odin
+++ b/vendor/x11/xlib/xlib_procs.odin
@@ -1,4 +1,4 @@
-//+build linux, openbsd, freebsd
+#+build linux, openbsd, freebsd
package xlib
foreign import xlib "system:X11"
diff --git a/vendor/x11/xlib/xlib_types.odin b/vendor/x11/xlib/xlib_types.odin
index b5de824e9..a73b8e8b8 100644
--- a/vendor/x11/xlib/xlib_types.odin
+++ b/vendor/x11/xlib/xlib_types.odin
@@ -1,4 +1,4 @@
-//+build linux, freebsd, openbsd
+#+build linux, freebsd, openbsd
package xlib
// Since this is a unix-only library we make a few simplifying assumptions
@@ -47,9 +47,9 @@ XExtCodes :: struct {
}
XPixmapFormatValues :: struct {
- depth: i32,
- bits_per_pixel: i32,
- scanline_pad: i32,
+ depth: i32,
+ bits_per_pixel: i32,
+ scanline_pad: i32,
}
XGCValues :: struct {
@@ -130,47 +130,47 @@ ScreenFormat :: struct {
}
XSetWindowAttributes :: struct {
- background_pixmap: Pixmap,
- background_pixel: uint,
- border_pixmap: Pixmap,
- border_pixel: uint,
- bit_gravity: Gravity,
- win_gravity: Gravity,
- backing_store: BackingStore,
- backing_planes: uint,
- backing_pixel: uint,
- save_under: b32,
- event_mask: EventMask,
- do_not_propagate_mask: EventMask,
- override_redirect: b32,
- colormap: Colormap,
- cursor: Cursor,
+ background_pixmap: Pixmap,
+ background_pixel: uint,
+ border_pixmap: Pixmap,
+ border_pixel: uint,
+ bit_gravity: Gravity,
+ win_gravity: Gravity,
+ backing_store: BackingStore,
+ backing_planes: uint,
+ backing_pixel: uint,
+ save_under: b32,
+ event_mask: EventMask,
+ do_not_propagate_mask: EventMask,
+ override_redirect: b32,
+ colormap: Colormap,
+ cursor: Cursor,
}
XWindowAttributes :: struct {
- x: i32,
- y: i32,
- width: i32,
- height: i32,
- border_width: i32,
- depth: i32,
- visual: ^Visual,
- root: Window,
- class: WindowClass,
- bit_gravity: Gravity,
- win_gravity: Gravity,
- backing_store: BackingStore,
- backing_planes: uint,
- backing_pixel: uint,
- save_under: b32,
- colormap: Colormap,
- map_installed: b32,
- map_state: WindowMapState,
- all_event_masks: EventMask,
- your_event_mask: EventMask,
- do_not_propagate_mask: EventMask,
- override_redirect: b32,
- screen: ^Screen,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ border_width: i32,
+ depth: i32,
+ visual: ^Visual,
+ root: Window,
+ class: WindowClass,
+ bit_gravity: Gravity,
+ win_gravity: Gravity,
+ backing_store: BackingStore,
+ backing_planes: uint,
+ backing_pixel: uint,
+ save_under: b32,
+ colormap: Colormap,
+ map_installed: b32,
+ map_state: WindowMapState,
+ all_event_masks: EventMask,
+ your_event_mask: EventMask,
+ do_not_propagate_mask: EventMask,
+ override_redirect: b32,
+ screen: ^Screen,
}
XHostAddress :: struct {
@@ -187,50 +187,50 @@ XServerInterpretedAddress :: struct {
}
XImage :: struct {
- width: i32,
- height: i32,
- xoffset: i32,
- format: ImageFormat,
- data: rawptr,
- byte_order: i32,
- bitmap_unit: i32,
- bitmap_bit_order: ByteOrder,
- bitmap_pad: i32,
- depth: i32,
- bytes_per_line: i32,
- bits_per_pixel: i32,
- red_mask: uint,
- green_mask: uint,
- blue_mask: uint,
- obdata: rawptr,
- f: struct {
- create_image: proc "c" (
- display: ^Display,
- visual: ^Visual,
- depth: u32,
- format: i32,
- offset: i32,
- data: rawptr,
- width: u32,
- height: u32,
- pad: i32,
- stride: i32) -> ^XImage,
- destroy_image: proc "c" (image: ^XImage) -> i32,
- get_pixel: proc "c" (image: ^XImage) -> uint,
- put_pixel: proc "c" (image: ^XImage, x: i32, y: i32, pixel: uint) -> i32,
- sub_image: proc "c" (image: ^XImage, x: i32, y: i32, w: u32, h: u32) -> ^XImage,
- add_pixel: proc "c" (image: ^XImage, val: int) -> i32,
+ width: i32,
+ height: i32,
+ xoffset: i32,
+ format: ImageFormat,
+ data: rawptr,
+ byte_order: i32,
+ bitmap_unit: i32,
+ bitmap_bit_order: ByteOrder,
+ bitmap_pad: i32,
+ depth: i32,
+ bytes_per_line: i32,
+ bits_per_pixel: i32,
+ red_mask: uint,
+ green_mask: uint,
+ blue_mask: uint,
+ obdata: rawptr,
+ f: struct {
+ create_image: proc "c" (
+ display: ^Display,
+ visual: ^Visual,
+ depth: u32,
+ format: i32,
+ offset: i32,
+ data: rawptr,
+ width: u32,
+ height: u32,
+ pad: i32,
+ stride: i32) -> ^XImage,
+ destroy_image: proc "c" (image: ^XImage) -> i32,
+ get_pixel: proc "c" (image: ^XImage) -> uint,
+ put_pixel: proc "c" (image: ^XImage, x: i32, y: i32, pixel: uint) -> i32,
+ sub_image: proc "c" (image: ^XImage, x: i32, y: i32, w: u32, h: u32) -> ^XImage,
+ add_pixel: proc "c" (image: ^XImage, val: int) -> i32,
},
}
XWindowChanges :: struct {
- x: i32,
- y: i32,
- width: i32,
- height: i32,
- border_width: i32,
- sibling: Window,
- stack_mode: WindowStacking,
+ x: i32,
+ y: i32,
+ width: i32,
+ height: i32,
+ border_width: i32,
+ sibling: Window,
+ stack_mode: WindowStacking,
}
XColor :: struct {
@@ -243,42 +243,42 @@ XColor :: struct {
}
XSegment :: struct {
- x1: i16,
- y1: i16,
- x2: i16,
- y2: i16,
+ x1: i16,
+ y1: i16,
+ x2: i16,
+ y2: i16,
}
XPoint :: struct {
- x: i16,
- y: i16,
+ x: i16,
+ y: i16,
}
XRectangle :: struct {
- x: i16,
- y: i16,
- width: u16,
- height: u16,
+ x: i16,
+ y: i16,
+ width: u16,
+ height: u16,
}
XArc :: struct {
- x: i16,
- y: i16,
- width: u16,
- height: u16,
- angle1: i16,
- angle2: i16,
+ x: i16,
+ y: i16,
+ width: u16,
+ height: u16,
+ angle1: i16,
+ angle2: i16,
}
XKeyboardControl :: struct {
- key_click_percent: i32,
- bell_percent: i32,
- bell_pitch: i32,
- bell_duration: i32,
- led: i32,
- led_mode: KeyboardLedMode,
- key: i32,
- auto_repeat_mode: KeyboardAutoRepeatMode,
+ key_click_percent: i32,
+ bell_percent: i32,
+ bell_pitch: i32,
+ bell_duration: i32,
+ led: i32,
+ led_mode: KeyboardLedMode,
+ key: i32,
+ auto_repeat_mode: KeyboardAutoRepeatMode,
}
XKeyboardState :: struct {
@@ -700,23 +700,23 @@ XAnyEvent :: struct {
}
XGenericEvent :: struct {
- type: EventType,
- serial: uint,
- send_event: b32,
- display: ^Display,
- extension: i32,
- evtype: i32,
+ type: EventType,
+ serial: uint,
+ send_event: b32,
+ display: ^Display,
+ extension: i32,
+ evtype: i32,
}
XGenericEventCookie :: struct {
- type: EventType,
- serial: uint,
- send_event: b32,
- display: ^Display,
- extension: i32,
- evtype: i32,
- cookie: u32,
- data: rawptr,
+ type: EventType,
+ serial: uint,
+ send_event: b32,
+ display: ^Display,
+ extension: i32,
+ evtype: i32,
+ cookie: u32,
+ data: rawptr,
}
XEvent :: struct #raw_union {
@@ -758,55 +758,55 @@ XEvent :: struct #raw_union {
}
XCharStruct :: struct {
- lbearing: i16,
- rbearing: i16,
- width: i16,
- ascent: i16,
- descent: i16,
- attributes: u16,
+ lbearing: i16,
+ rbearing: i16,
+ width: i16,
+ ascent: i16,
+ descent: i16,
+ attributes: u16,
}
XFontProp :: struct {
- name: Atom,
- card32: uint,
+ name: Atom,
+ card32: uint,
}
XFontStruct :: struct {
- ext_data: ^XExtData,
- fid: Font,
- direction: u32,
- min_char_or_byte2: u32,
- max_char_or_byte2: u32,
- min_byte1: u32,
- max_byte1: u32,
- all_chars_exist: i32,
- default_char: u32,
- n_properties: i32,
- properties: ^XFontProp,
- min_bounds: XCharStruct,
- max_bounds: XCharStruct,
- per_char: ^XCharStruct,
- ascent: i32,
- descent: i32,
+ ext_data: ^XExtData,
+ fid: Font,
+ direction: u32,
+ min_char_or_byte2: u32,
+ max_char_or_byte2: u32,
+ min_byte1: u32,
+ max_byte1: u32,
+ all_chars_exist: i32,
+ default_char: u32,
+ n_properties: i32,
+ properties: ^XFontProp,
+ min_bounds: XCharStruct,
+ max_bounds: XCharStruct,
+ per_char: ^XCharStruct,
+ ascent: i32,
+ descent: i32,
}
XTextItem :: struct {
- chars: [^]u8,
- nchars: i32,
- delta: i32,
- font: Font,
+ chars: [^]u8,
+ nchars: i32,
+ delta: i32,
+ font: Font,
}
XChar2b :: struct {
- byte1: u8,
- byte2: u8,
+ byte1: u8,
+ byte2: u8,
}
XTextItem16 :: struct {
- chars: ^XChar2b,
- nchars: i32,
- delta: i32,
- font: Font,
+ chars: ^XChar2b,
+ nchars: i32,
+ delta: i32,
+ font: Font,
}
XEDataObject :: struct #raw_union {
@@ -819,8 +819,8 @@ XEDataObject :: struct #raw_union {
}
XFontSetExtents :: struct {
- max_ink_extent: XRectangle,
- max_logical_extent: XRectangle,
+ max_ink_extent: XRectangle,
+ max_logical_extent: XRectangle,
}
XOM :: distinct rawptr
@@ -828,41 +828,41 @@ XOC :: distinct rawptr
XFontSet :: XOC
XmbTextItem :: struct {
- chars: [^]u8,
- nchars: i32,
- delta: i32,
- font_set: XFontSet,
+ chars: [^]u8,
+ nchars: i32,
+ delta: i32,
+ font_set: XFontSet,
}
XwcTextItem :: struct {
- chars: [^]rune,
- nchars: i32,
- delta: i32,
- font_set: XFontSet,
+ chars: [^]rune,
+ nchars: i32,
+ delta: i32,
+ font_set: XFontSet,
}
XOMCharSetList :: struct {
- charset_count: i32,
- charset_list: [^]cstring,
+ charset_count: i32,
+ charset_list: [^]cstring,
}
XOrientation :: enum i32 {
- XOMOrientation_LTR_TTB = 0,
- XOMOrientation_RTL_TTB = 1,
- XOMOrientation_TTB_LTR = 2,
- XOMOrientation_TTB_RTL = 3,
- XOMOrientation_Context = 4,
+ XOMOrientation_LTR_TTB = 0,
+ XOMOrientation_RTL_TTB = 1,
+ XOMOrientation_TTB_LTR = 2,
+ XOMOrientation_TTB_RTL = 3,
+ XOMOrientation_Context = 4,
}
XOMOrientation :: struct {
- num_orientation: i32,
- orientation: [^]XOrientation,
+ num_orientation: i32,
+ orientation: [^]XOrientation,
}
XOMFontInfo :: struct {
- num_font: i32,
- font_struct_list: [^]^XFontStruct,
- font_name_list: [^]cstring,
+ num_font: i32,
+ font_struct_list: [^]^XFontStruct,
+ font_name_list: [^]cstring,
}
XIM :: distinct rawptr
@@ -875,38 +875,38 @@ XIDProc :: #type proc "c" (xim: XIM, client_data: rawptr, call_data: rawptr)
XIMStyle :: uint
XIMStyles :: struct {
- count_styles: u16,
- supported_styles: [^]XIMStyle,
+ count_styles: u16,
+ supported_styles: [^]XIMStyle,
}
XVaNestedList :: distinct rawptr
XIMCallback :: struct {
- client_data: rawptr,
- callback: XIMProc,
+ client_data: rawptr,
+ callback: XIMProc,
}
XICCallback :: struct {
- client_data: rawptr,
- callback: XICProc,
+ client_data: rawptr,
+ callback: XICProc,
}
XIMFeedback :: uint
XIMText :: struct {
- length: u16,
- feedback: ^XIMFeedback,
- encoding_is_wchar: b32,
- string: struct #raw_union {
+ length: u16,
+ feedback: ^XIMFeedback,
+ encoding_is_wchar: b32,
+ string: struct #raw_union {
multi_byte: [^]u8,
wide_char: [^]rune,
- },
+ },
}
XIMPreeditState :: uint
XIMPreeditStateNotifyCallbackStruct :: struct {
- state: XIMPreeditState,
+ state: XIMPreeditState,
}
XIMResetState :: uint
@@ -914,13 +914,13 @@ XIMResetState :: uint
XIMStringConversionFeedback :: uint
XIMStringConversionText :: struct {
- length: u16,
- feedback: ^XIMStringConversionFeedback,
- encoding_is_wchar: b32,
- string: struct #raw_union {
+ length: u16,
+ feedback: ^XIMStringConversionFeedback,
+ encoding_is_wchar: b32,
+ string: struct #raw_union {
mbs: [^]u8,
wcs: [^]rune,
- },
+ },
}
XIMStringConversionPosition :: u16
@@ -928,76 +928,76 @@ XIMStringConversionType :: u16
XIMStringConversionOperation :: u16
XIMCaretDirection :: enum i32 {
- XIMForwardChar = 0,
- XIMBackwardChar = 1,
- XIMForwardWord = 2,
- XIMBackwardWord = 3,
- XIMCaretUp = 4,
- XIMCaretDown = 5,
- XIMNextLine = 6,
- XIMPreviousLine = 7,
- XIMLineStart = 8,
- XIMLineEnd = 9,
- XIMAbsolutePosition = 10,
- XIMDontChang = 11,
+ XIMForwardChar = 0,
+ XIMBackwardChar = 1,
+ XIMForwardWord = 2,
+ XIMBackwardWord = 3,
+ XIMCaretUp = 4,
+ XIMCaretDown = 5,
+ XIMNextLine = 6,
+ XIMPreviousLine = 7,
+ XIMLineStart = 8,
+ XIMLineEnd = 9,
+ XIMAbsolutePosition = 10,
+ XIMDontChang = 11,
}
XIMStringConversionCallbackStruct :: struct {
- position: XIMStringConversionPosition,
- direction: XIMCaretDirection,
- operation: XIMStringConversionOperation,
- factor: u16,
- text: ^XIMStringConversionText,
+ position: XIMStringConversionPosition,
+ direction: XIMCaretDirection,
+ operation: XIMStringConversionOperation,
+ factor: u16,
+ text: ^XIMStringConversionText,
}
XIMPreeditDrawCallbackStruct :: struct {
- caret: i32,
- chg_first: i32,
- chg_length: i32,
- text: ^XIMText,
+ caret: i32,
+ chg_first: i32,
+ chg_length: i32,
+ text: ^XIMText,
}
XIMCaretStyle :: enum i32 {
- XIMIsInvisible,
- XIMIsPrimary,
- XIMIsSecondary,
+ XIMIsInvisible,
+ XIMIsPrimary,
+ XIMIsSecondary,
}
XIMPreeditCaretCallbackStruct :: struct {
- position: i32,
- direction: XIMCaretDirection,
- style: XIMCaretStyle,
+ position: i32,
+ direction: XIMCaretDirection,
+ style: XIMCaretStyle,
}
XIMStatusDataType :: enum {
- XIMTextType,
- XIMBitmapType,
+ XIMTextType,
+ XIMBitmapType,
}
XIMStatusDrawCallbackStruct :: struct {
- type: XIMStatusDataType,
- data: struct #raw_union {
+ type: XIMStatusDataType,
+ data: struct #raw_union {
text: ^XIMText,
bitmap: Pixmap,
- },
+ },
}
XIMHotKeyTrigger :: struct {
- keysym: KeySym,
- modifier: i32,
- modifier_mask: i32,
+ keysym: KeySym,
+ modifier: i32,
+ modifier_mask: i32,
}
XIMHotKeyTriggers :: struct {
- num_hot_key: i32,
- key: [^]XIMHotKeyTrigger,
+ num_hot_key: i32,
+ key: [^]XIMHotKeyTrigger,
}
XIMHotKeyState :: uint
XIMValuesList :: struct {
- count_values: u16,
- supported_values: [^]cstring,
+ count_values: u16,
+ supported_values: [^]cstring,
}
XConnectionWatchProc :: #type proc "c" (
@@ -1775,62 +1775,62 @@ XcmsColorFormat :: uint
XcmsFloat :: f64
XcmsRGB :: struct {
- red: u16,
- green: u16,
- blue: u16,
+ red: u16,
+ green: u16,
+ blue: u16,
}
XcmsRGBi :: struct {
- red: XcmsFloat,
- green: XcmsFloat,
- blue: XcmsFloat,
+ red: XcmsFloat,
+ green: XcmsFloat,
+ blue: XcmsFloat,
}
XcmsCIEXYZ :: struct {
- X: XcmsFloat,
- Y: XcmsFloat,
- Z: XcmsFloat,
+ X: XcmsFloat,
+ Y: XcmsFloat,
+ Z: XcmsFloat,
}
XcmsCIEuvY :: struct {
- u_prime: XcmsFloat,
- v_prime: XcmsFloat,
- Y: XcmsFloat,
+ u_prime: XcmsFloat,
+ v_prime: XcmsFloat,
+ Y: XcmsFloat,
}
XcmsCIExyY :: struct {
- x: XcmsFloat,
- y: XcmsFloat,
- Y: XcmsFloat,
+ x: XcmsFloat,
+ y: XcmsFloat,
+ Y: XcmsFloat,
}
XcmsCIELab :: struct {
- L_star: XcmsFloat,
- a_star: XcmsFloat,
- b_star: XcmsFloat,
+ L_star: XcmsFloat,
+ a_star: XcmsFloat,
+ b_star: XcmsFloat,
}
XcmsCIELuv :: struct {
- L_star: XcmsFloat,
- u_star: XcmsFloat,
- v_star: XcmsFloat,
+ L_star: XcmsFloat,
+ u_star: XcmsFloat,
+ v_star: XcmsFloat,
}
XcmsTekHVC :: struct {
- H: XcmsFloat,
- V: XcmsFloat,
- C: XcmsFloat,
+ H: XcmsFloat,
+ V: XcmsFloat,
+ C: XcmsFloat,
}
XcmsPad :: struct {
- _: XcmsFloat,
- _: XcmsFloat,
- _: XcmsFloat,
- _: XcmsFloat,
+ _: XcmsFloat,
+ _: XcmsFloat,
+ _: XcmsFloat,
+ _: XcmsFloat,
}
XcmsColor :: struct {
- spec: struct #raw_union {
+ spec: struct #raw_union {
RGB: XcmsRGB,
RGBi: XcmsRGBi,
CIEXYZ: XcmsCIEXYZ,
@@ -1840,17 +1840,17 @@ XcmsColor :: struct {
CIELuv: XcmsCIELuv,
TekHVC: XcmsTekHVC,
_: XcmsPad,
- },
- pixel: uint,
- format: XcmsColorFormat,
+ },
+ pixel: uint,
+ format: XcmsColorFormat,
}
XcmsPerScrnInfo :: struct {
- screenWhitePt: XcmsColor,
- functionSet: rawptr,
- screenData: rawptr,
- state: u8,
- _: [3]u8,
+ screenWhitePt: XcmsColor,
+ functionSet: rawptr,
+ screenData: rawptr,
+ state: u8,
+ _: [3]u8,
}
XcmsCCC :: distinct rawptr
@@ -1872,15 +1872,15 @@ XcmsWhiteAdjustProc :: #type proc "c" (
compression: [^]b32) -> Status
XcmsCCCRec :: struct {
- dpy: ^Display,
- screenNumber: i32,
- visual: ^Visual,
- clientWhitePt: XcmsColor,
- gamutCompProc: XcmsCompressionProc,
- gamutCompClientData: rawptr,
- whitePtAdjProc: XcmsWhiteAdjustProc,
- whitePtAdjClientData: rawptr,
- pPerScrnInfo: ^XcmsPerScrnInfo,
+ dpy: ^Display,
+ screenNumber: i32,
+ visual: ^Visual,
+ clientWhitePt: XcmsColor,
+ gamutCompProc: XcmsCompressionProc,
+ gamutCompClientData: rawptr,
+ whitePtAdjProc: XcmsWhiteAdjustProc,
+ whitePtAdjClientData: rawptr,
+ pPerScrnInfo: ^XcmsPerScrnInfo,
}
XcmsScreenInitProc :: #type proc "c" (
@@ -1909,18 +1909,18 @@ XcmsFuncListPtr :: [^]XcmsConversionProc
XcmsParseStringProc :: #type proc "c" (color_string: cstring, color: ^XcmsColor) -> i32
XcmsColorSpace :: struct {
- prefix: cstring,
- id: XcmsColorFormat,
- parseString: XcmsParseStringProc,
- to_CIEXYZ: XcmsFuncListPtr,
- from_CIEXYZ: XcmsFuncListPtr,
- inverse_flag: i32,
+ prefix: cstring,
+ id: XcmsColorFormat,
+ parseString: XcmsParseStringProc,
+ to_CIEXYZ: XcmsFuncListPtr,
+ from_CIEXYZ: XcmsFuncListPtr,
+ inverse_flag: i32,
}
XcmsFunctionSet :: struct {
- DDColorSpaces: [^]^XcmsColorSpace,
- screenInitProc: XcmsScreenInitProc,
- screenFreeProc: XcmsScreenFreeProc,
+ DDColorSpaces: [^]^XcmsColorSpace,
+ screenInitProc: XcmsScreenInitProc,
+ screenFreeProc: XcmsScreenFreeProc,
}
@@ -1958,18 +1958,18 @@ XWMHints :: struct {
}
XTextProperty :: struct {
- value: [^]u8,
- encoding: Atom,
- format: int,
- nitems: uint,
+ value: [^]u8,
+ encoding: Atom,
+ format: int,
+ nitems: uint,
}
XICCEncodingStyle :: enum i32 {
- XStringStyle,
- XCompoundTextStyle,
- XTextStyle,
- XStdICCTextStyle,
- XUTF8StringStyle,
+ XStringStyle,
+ XCompoundTextStyle,
+ XTextStyle,
+ XStdICCTextStyle,
+ XUTF8StringStyle,
}
XIconSize :: struct {
@@ -1987,8 +1987,8 @@ XClassHint :: struct {
}
XComposeStatus :: struct {
- compose_ptr: rawptr,
- chars_matched: i32,
+ compose_ptr: rawptr,
+ chars_matched: i32,
}
Region :: distinct rawptr
@@ -2041,8 +2041,8 @@ XrmClassList :: XrmQuarkList
XrmRepresentation :: XrmQuark
XrmValue :: struct {
- size: u32,
- addr: rawptr,
+ size: u32,
+ addr: rawptr,
}
XrmValuePtr :: [^]XrmValue
@@ -2052,21 +2052,21 @@ XrmSearchList :: [^]XrmHashTable
XrmDatabase :: distinct rawptr
XrmOptionKind :: enum {
- XrmoptionNoArg,
- XrmoptionIsArg,
- XrmoptionStickyArg,
- XrmoptionSepArg,
- XrmoptionResArg,
- XrmoptionSkipArg,
- XrmoptionSkipLine,
- XrmoptionSkipNArgs,
+ XrmoptionNoArg,
+ XrmoptionIsArg,
+ XrmoptionStickyArg,
+ XrmoptionSepArg,
+ XrmoptionResArg,
+ XrmoptionSkipArg,
+ XrmoptionSkipLine,
+ XrmoptionSkipNArgs,
}
XrmOptionDescRec :: struct {
- option: cstring,
- specifier: cstring,
- argKind: XrmOptionKind,
- value: rawptr,
+ option: cstring,
+ specifier: cstring,
+ argKind: XrmOptionKind,
+ value: rawptr,
}
XrmOptionDescList :: [^]XrmOptionDescRec