mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-20 21:35:19 +00:00
Merge branch 'odin-lang:master' into master
This commit is contained in:
1
.github/workflows/nightly.yml
vendored
1
.github/workflows/nightly.yml
vendored
@@ -50,6 +50,7 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp libLLVM*.so dist
|
||||
cp -r shared dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -271,6 +271,7 @@ odin
|
||||
odin.dSYM
|
||||
*.bin
|
||||
demo.bin
|
||||
libLLVM*.so
|
||||
|
||||
# shared collection
|
||||
shared/
|
||||
@@ -283,3 +284,4 @@ shared/
|
||||
*.sublime-workspace
|
||||
examples/bug/
|
||||
build.sh
|
||||
!core/debug/
|
||||
@@ -99,7 +99,8 @@ config_linux() {
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
|
||||
cp $($LLVM_CONFIG --libfiles) ./
|
||||
}
|
||||
|
||||
build_odin() {
|
||||
|
||||
@@ -49,8 +49,8 @@ foreign libc {
|
||||
// 7.3.8 Power and absolute-value functions
|
||||
cabs :: proc(z: complex_double) -> complex_double ---
|
||||
cabsf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(z: complex_double) -> complex_double ---
|
||||
cpowf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(x, y: complex_double) -> complex_double ---
|
||||
cpowf :: proc(x, y: complex_float) -> complex_float ---
|
||||
csqrt :: proc(z: complex_double) -> complex_double ---
|
||||
csqrtf :: proc(z: complex_float) -> complex_float ---
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ foreign libc {
|
||||
srand :: proc(seed: uint) ---
|
||||
|
||||
// 7.22.3 Memory management functions
|
||||
aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---
|
||||
calloc :: proc(nmemb, size: size_t) -> rawptr ---
|
||||
free :: proc(ptr: rawptr) ---
|
||||
malloc :: proc(size: size_t) -> rawptr ---
|
||||
@@ -125,3 +124,30 @@ foreign libc {
|
||||
mbstowcs :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
|
||||
wcstombs :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
|
||||
}
|
||||
|
||||
|
||||
aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
|
||||
}
|
||||
return _aligned_malloc(size=size, alignment=alignment)
|
||||
} else {
|
||||
foreign libc {
|
||||
aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
|
||||
}
|
||||
return aligned_alloc(alignment=alignment, size=size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
aligned_free :: #force_inline proc "c" (ptr: rawptr) {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_free :: proc(ptr: rawptr) ---
|
||||
}
|
||||
_aligned_free(ptr)
|
||||
} else {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
221
core/debug/pe/pe.odin
Normal file
221
core/debug/pe/pe.odin
Normal file
@@ -0,0 +1,221 @@
|
||||
package debug_pe
|
||||
|
||||
PE_SIGNATURE_OFFSET_INDEX_POS :: 0x3c
|
||||
PE_SIGNATURE :: u32le(0x0000_4550) // "PE\x00\x00"
|
||||
PE_SIGNATURE_STRING :: "PE\x00\x00"
|
||||
|
||||
OPTIONAL_HEADER_MAGIC :: enum u16le {
|
||||
PE32 = 0x010b,
|
||||
PE32_PLUS = 0x020b,
|
||||
}
|
||||
|
||||
Optional_Header_Base :: struct #packed {
|
||||
magic: OPTIONAL_HEADER_MAGIC,
|
||||
major_linker_version: u8,
|
||||
minor_linker_version: u8,
|
||||
size_of_code: u32le,
|
||||
size_of_initialized_data: u32le,
|
||||
size_of_uninitialized_data: u32le,
|
||||
address_of_entry_point: u32le,
|
||||
base_of_code: u32le,
|
||||
}
|
||||
|
||||
File_Header :: struct #packed {
|
||||
machine: IMAGE_FILE_MACHINE,
|
||||
number_of_sections: u16le,
|
||||
time_date_stamp: u32le,
|
||||
pointer_to_symbol_table: u32le,
|
||||
number_of_symbols: u32le,
|
||||
size_of_optional_header: u16le,
|
||||
characteristics: IMAGE_FILE_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Data_Directory :: struct #packed {
|
||||
virtual_address: u32le,
|
||||
size: u32le,
|
||||
}
|
||||
|
||||
Optional_Header32 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
base_of_data: u32le,
|
||||
image_base: u32le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u32le,
|
||||
size_of_stack_commit: u32le,
|
||||
size_of_heap_reserve: u32le,
|
||||
size_of_heap_commit: u32le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
Optional_Header64 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
image_base: u64le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u64le,
|
||||
size_of_stack_commit: u64le,
|
||||
size_of_heap_reserve: u64le,
|
||||
size_of_heap_commit: u64le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
// .debug section
|
||||
Debug_Directory_Entry :: struct {
|
||||
characteristics: u32le,
|
||||
time_date_stamp: u32le,
|
||||
major_version: u16le,
|
||||
minor_version: u16le,
|
||||
type: IMAGE_DEBUG_TYPE,
|
||||
size_of_data: u32le,
|
||||
address_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
}
|
||||
|
||||
|
||||
IMAGE_FILE_MACHINE :: enum u16le {
|
||||
UNKNOWN = 0x0,
|
||||
AM33 = 0x1d3,
|
||||
AMD64 = 0x8664,
|
||||
ARM = 0x1c0,
|
||||
ARMNT = 0x1c4,
|
||||
ARM64 = 0xaa64,
|
||||
EBC = 0xebc,
|
||||
I386 = 0x14c,
|
||||
IA64 = 0x200,
|
||||
LOONGARCH32 = 0x6232,
|
||||
LOONGARCH64 = 0x6264,
|
||||
M32R = 0x9041,
|
||||
MIPS16 = 0x266,
|
||||
MIPSFPU = 0x366,
|
||||
MIPSFPU16 = 0x466,
|
||||
POWERPC = 0x1f0,
|
||||
POWERPCFP = 0x1f1,
|
||||
R4000 = 0x166,
|
||||
SH3 = 0x1a2,
|
||||
SH3DSP = 0x1a3,
|
||||
SH4 = 0x1a6,
|
||||
SH5 = 0x1a8,
|
||||
THUMB = 0x1c2,
|
||||
WCEMIPSV2 = 0x169,
|
||||
}
|
||||
|
||||
// IMAGE_DIRECTORY_ENTRY constants
|
||||
IMAGE_DIRECTORY_ENTRY :: enum u8 {
|
||||
EXPORT = 0,
|
||||
IMPORT = 1,
|
||||
RESOURCE = 2,
|
||||
EXCEPTION = 3,
|
||||
SECURITY = 4,
|
||||
BASERELOC = 5,
|
||||
DEBUG = 6,
|
||||
ARCHITECTURE = 7, // reserved
|
||||
GLOBALPTR = 8,
|
||||
TLS = 9,
|
||||
LOAD_CONFIG = 10,
|
||||
BOUND_IMPORT = 11,
|
||||
IAT = 12,
|
||||
DELAY_IMPORT = 13,
|
||||
COM_DESCRIPTOR = 14, // DLR Runtime headers
|
||||
_RESERVED = 15,
|
||||
}
|
||||
#assert(len(IMAGE_DIRECTORY_ENTRY) == 16)
|
||||
|
||||
|
||||
IMAGE_FILE_CHARACTERISTICS :: distinct bit_set[IMAGE_FILE_CHARACTERISTIC; u16le]
|
||||
IMAGE_FILE_CHARACTERISTIC :: enum u16le {
|
||||
RELOCS_STRIPPED = 0,
|
||||
EXECUTABLE_IMAGE = 1,
|
||||
LINE_NUMS_STRIPPED = 2,
|
||||
LOCAL_SYMS_STRIPPED = 3,
|
||||
AGGRESIVE_WS_TRIM = 4,
|
||||
LARGE_ADDRESS_AWARE = 5,
|
||||
|
||||
BYTES_REVERSED_LO = 7,
|
||||
MACHINE_32BIT = 8, // IMAGE_FILE_32BIT_MACHINE originally
|
||||
DEBUG_STRIPPED = 9,
|
||||
REMOVABLE_RUN_FROM_SWAP = 10,
|
||||
NET_RUN_FROM_SWAP = 11,
|
||||
SYSTEM = 12,
|
||||
DLL = 13,
|
||||
UP_SYSTEM_ONLY = 14,
|
||||
BYTES_REVERSED_HI = 15,
|
||||
}
|
||||
|
||||
IMAGE_SUBSYSTEM :: enum u16le {
|
||||
UNKNOWN = 0,
|
||||
NATIVE = 1,
|
||||
WINDOWS_GUI = 2,
|
||||
WINDOWS_CUI = 3,
|
||||
OS2_CUI = 5,
|
||||
POSIX_CUI = 7,
|
||||
NATIVE_WINDOWS = 8,
|
||||
WINDOWS_CE_GUI = 9,
|
||||
EFI_APPLICATION = 10,
|
||||
EFI_BOOT_SERVICE_DRIVER = 11,
|
||||
EFI_RUNTIME_DRIVER = 12,
|
||||
EFI_ROM = 13,
|
||||
XBOX = 14,
|
||||
WINDOWS_BOOT_APPLICATION = 16,
|
||||
}
|
||||
|
||||
IMAGE_DLLCHARACTERISTICS :: distinct bit_set[IMAGE_DLLCHARACTERISTIC; u16le]
|
||||
IMAGE_DLLCHARACTERISTIC :: enum u16le {
|
||||
HIGH_ENTROPY_VA = 5,
|
||||
DYNAMIC_BASE = 6,
|
||||
FORCE_INTEGRITY = 7,
|
||||
NX_COMPAT = 8,
|
||||
NO_ISOLATION = 9,
|
||||
NO_SEH = 10,
|
||||
NO_BIND = 11,
|
||||
APPCONTAINER = 12,
|
||||
WDM_DRIVER = 13,
|
||||
GUARD_CF = 14,
|
||||
TERMINAL_SERVER_AWARE = 15,
|
||||
}
|
||||
|
||||
IMAGE_DEBUG_TYPE :: enum u32le {
|
||||
UNKNOWN = 0, // An unknown value that is ignored by all tools.
|
||||
COFF = 1, // The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
|
||||
CODEVIEW = 2, // The Visual C++ debug information.
|
||||
FPO = 3, // The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
|
||||
MISC = 4, // The location of DBG file.
|
||||
EXCEPTION = 5, // A copy of .pdata section.
|
||||
FIXUP = 6, // Reserved.
|
||||
OMAP_TO_SRC = 7, // The mapping from an RVA in image to an RVA in source image.
|
||||
OMAP_FROM_SRC = 8, // The mapping from an RVA in source image to an RVA in image.
|
||||
BORLAND = 9, // Reserved for Borland.
|
||||
RESERVED10 = 10, // Reserved.
|
||||
CLSID = 11, // Reserved.
|
||||
REPRO = 16, // PE determinism or reproducibility.
|
||||
EX_DLLCHARACTERISTICS = 20, // Extended DLL characteristics bits.
|
||||
}
|
||||
|
||||
131
core/debug/pe/section.odin
Normal file
131
core/debug/pe/section.odin
Normal file
@@ -0,0 +1,131 @@
|
||||
package debug_pe
|
||||
|
||||
import "core:runtime"
|
||||
import "core:io"
|
||||
|
||||
Section_Header32 :: struct {
|
||||
name: [8]u8,
|
||||
virtual_size: u32le,
|
||||
virtual_address: u32le,
|
||||
size_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
pointer_to_relocations: u32le,
|
||||
pointer_to_line_numbers: u32le,
|
||||
number_of_relocations: u16le,
|
||||
number_of_line_numbers: u16le,
|
||||
characteristics: IMAGE_SCN_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Reloc :: struct {
|
||||
virtual_address: u32le,
|
||||
symbol_table_index: u32le,
|
||||
type: IMAGE_REL,
|
||||
}
|
||||
|
||||
IMAGE_SCN_CHARACTERISTICS :: enum u32le {
|
||||
TYPE_NO_PAD = 0x00000008, // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. = 0x00000010, // Reserved for future use.
|
||||
CNT_CODE = 0x00000020, // The section contains executable code.
|
||||
CNT_INITIALIZED_DATA = 0x00000040, // The section contains initialized data.
|
||||
CNT_UNINITIALIZED_DATA = 0x00000080, // The section contains uninitialized data.
|
||||
LNK_OTHER = 0x00000100, // Reserved for future use.
|
||||
LNK_INFO = 0x00000200, // The section contains comments or other information. The .drectve section has this type. This is valid for object files only. = 0x00000400, // Reserved for future use.
|
||||
LNK_REMOVE = 0x00000800, // The section will not become part of the image. This is valid only for object files.
|
||||
LNK_COMDAT = 0x00001000, // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
|
||||
GPREL = 0x00008000, // The section contains data referenced through the global pointer (GP).
|
||||
MEM_PURGEABLE = 0x00020000, // Reserved for future use.
|
||||
MEM_16BIT = 0x00020000, // Reserved for future use.
|
||||
MEM_LOCKED = 0x00040000, // Reserved for future use.
|
||||
MEM_PRELOAD = 0x00080000, // Reserved for future use.
|
||||
ALIGN_1BYTES = 0x00100000, // Align data on a 1-byte boundary. Valid only for object files.
|
||||
ALIGN_2BYTES = 0x00200000, // Align data on a 2-byte boundary. Valid only for object files.
|
||||
ALIGN_4BYTES = 0x00300000, // Align data on a 4-byte boundary. Valid only for object files.
|
||||
ALIGN_8BYTES = 0x00400000, // Align data on an 8-byte boundary. Valid only for object files.
|
||||
ALIGN_16BYTES = 0x00500000, // Align data on a 16-byte boundary. Valid only for object files.
|
||||
ALIGN_32BYTES = 0x00600000, // Align data on a 32-byte boundary. Valid only for object files.
|
||||
ALIGN_64BYTES = 0x00700000, // Align data on a 64-byte boundary. Valid only for object files.
|
||||
ALIGN_128BYTES = 0x00800000, // Align data on a 128-byte boundary. Valid only for object files.
|
||||
ALIGN_256BYTES = 0x00900000, // Align data on a 256-byte boundary. Valid only for object files.
|
||||
ALIGN_512BYTES = 0x00A00000, // Align data on a 512-byte boundary. Valid only for object files.
|
||||
ALIGN_1024BYTES = 0x00B00000, // Align data on a 1024-byte boundary. Valid only for object files.
|
||||
ALIGN_2048BYTES = 0x00C00000, // Align data on a 2048-byte boundary. Valid only for object files.
|
||||
ALIGN_4096BYTES = 0x00D00000, // Align data on a 4096-byte boundary. Valid only for object files.
|
||||
ALIGN_8192BYTES = 0x00E00000, // Align data on an 8192-byte boundary. Valid only for object files.
|
||||
LNK_NRELOC_OVFL = 0x01000000, // The section contains extended relocations.
|
||||
MEM_DISCARDABLE = 0x02000000, // The section can be discarded as needed.
|
||||
MEM_NOT_CACHED = 0x04000000, // The section cannot be cached.
|
||||
MEM_NOT_PAGED = 0x08000000, // The section is not pageable.
|
||||
MEM_SHARED = 0x10000000, // The section can be shared in memory.
|
||||
MEM_EXECUTE = 0x20000000, // The section can be executed as code.
|
||||
MEM_READ = 0x40000000, // The section can be read.
|
||||
MEM_WRITE = 0x80000000, // The section can be written to.
|
||||
}
|
||||
|
||||
|
||||
IMAGE_REL :: enum u16le {
|
||||
I386_ABSOLUTE = 0x0000,
|
||||
I386_DIR16 = 0x0001,
|
||||
I386_REL16 = 0x0002,
|
||||
I386_DIR32 = 0x0006,
|
||||
I386_DIR32NB = 0x0007,
|
||||
I386_SEG12 = 0x0009,
|
||||
I386_SECTION = 0x000A,
|
||||
I386_SECREL = 0x000B,
|
||||
I386_TOKEN = 0x000C,
|
||||
I386_SECREL7 = 0x000D,
|
||||
I386_REL32 = 0x0014,
|
||||
|
||||
AMD64_ABSOLUTE = 0x0000,
|
||||
AMD64_ADDR64 = 0x0001,
|
||||
AMD64_ADDR32 = 0x0002,
|
||||
AMD64_ADDR32NB = 0x0003,
|
||||
AMD64_REL32 = 0x0004,
|
||||
AMD64_REL32_1 = 0x0005,
|
||||
AMD64_REL32_2 = 0x0006,
|
||||
AMD64_REL32_3 = 0x0007,
|
||||
AMD64_REL32_4 = 0x0008,
|
||||
AMD64_REL32_5 = 0x0009,
|
||||
AMD64_SECTION = 0x000A,
|
||||
AMD64_SECREL = 0x000B,
|
||||
AMD64_SECREL7 = 0x000C,
|
||||
AMD64_TOKEN = 0x000D,
|
||||
AMD64_SREL32 = 0x000E,
|
||||
AMD64_PAIR = 0x000F,
|
||||
AMD64_SSPAN32 = 0x0010,
|
||||
|
||||
ARM_ABSOLUTE = 0x0000,
|
||||
ARM_ADDR32 = 0x0001,
|
||||
ARM_ADDR32NB = 0x0002,
|
||||
ARM_BRANCH24 = 0x0003,
|
||||
ARM_BRANCH11 = 0x0004,
|
||||
ARM_SECTION = 0x000E,
|
||||
ARM_SECREL = 0x000F,
|
||||
ARM_MOV32 = 0x0010,
|
||||
|
||||
THUMB_MOV32 = 0x0011,
|
||||
THUMB_BRANCH20 = 0x0012,
|
||||
THUMB_BRANCH24 = 0x0014,
|
||||
THUMB_BLX23 = 0x0015,
|
||||
|
||||
ARM_PAIR = 0x0016,
|
||||
|
||||
ARM64_ABSOLUTE = 0x0000,
|
||||
ARM64_ADDR32 = 0x0001,
|
||||
ARM64_ADDR32NB = 0x0002,
|
||||
ARM64_BRANCH26 = 0x0003,
|
||||
ARM64_PAGEBASE_REL21 = 0x0004,
|
||||
ARM64_REL21 = 0x0005,
|
||||
ARM64_PAGEOFFSET_12A = 0x0006,
|
||||
ARM64_PAGEOFFSET_12L = 0x0007,
|
||||
ARM64_SECREL = 0x0008,
|
||||
ARM64_SECREL_LOW12A = 0x0009,
|
||||
ARM64_SECREL_HIGH12A = 0x000A,
|
||||
ARM64_SECREL_LOW12L = 0x000B,
|
||||
ARM64_TOKEN = 0x000C,
|
||||
ARM64_SECTION = 0x000D,
|
||||
ARM64_ADDR64 = 0x000E,
|
||||
ARM64_BRANCH19 = 0x000F,
|
||||
ARM64_BRANCH14 = 0x0010,
|
||||
ARM64_REL32 = 0x0011,
|
||||
}
|
||||
|
||||
PE_CODE_VIEW_SIGNATURE_RSDS :: u32le(0x5344_5352)
|
||||
108
core/debug/pe/symbol.odin
Normal file
108
core/debug/pe/symbol.odin
Normal file
@@ -0,0 +1,108 @@
|
||||
package debug_pe
|
||||
|
||||
COFF_SYMBOL_SIZE :: 18
|
||||
|
||||
COFF_Symbol :: struct {
|
||||
name: [8]u8,
|
||||
value: u32le,
|
||||
section_number: i16le,
|
||||
type: IMAGE_SYM_TYPE,
|
||||
storage_class: IMAGE_SYM_CLASS,
|
||||
number_of_aux_symbols: u8,
|
||||
}
|
||||
|
||||
// COFF_Symbol_Aux_Format5 describes the expected form of an aux symbol
|
||||
// attached to a section definition symbol. The PE format defines a
|
||||
// number of different aux symbol formats: format 1 for function
|
||||
// definitions, format 2 for .be and .ef symbols, and so on. Format 5
|
||||
// holds extra info associated with a section definition, including
|
||||
// number of relocations + line numbers, as well as COMDAT info. See
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
|
||||
// for more on what's going on here.
|
||||
COFF_Symbol_Aux_Format5 :: struct {
|
||||
size: u32le,
|
||||
num_relocs: u16le,
|
||||
num_line_numbers: u16le,
|
||||
checksum: u32le,
|
||||
sec_num: u16le,
|
||||
selection: IMAGE_COMDAT_SELECT,
|
||||
_: [3]u8, // padding
|
||||
}
|
||||
|
||||
IMAGE_COMDAT_SELECT :: enum u8 {
|
||||
NODUPLICATES = 1,
|
||||
ANY = 2,
|
||||
SAME_SIZE = 3,
|
||||
EXACT_MATCH = 4,
|
||||
ASSOCIATIVE = 5,
|
||||
LARGEST = 6,
|
||||
}
|
||||
|
||||
|
||||
// The symbol record is not yet assigned a section. A value of zero indicates
|
||||
// that a reference to an external symbol is defined elsewhere. A value of
|
||||
// non-zero is a common symbol with a size that is specified by the value.
|
||||
IMAGE_SYM_UNDEFINED :: 0
|
||||
// The symbol has an absolute (non-relocatable) value and is not an address.
|
||||
IMAGE_SYM_ABSOLUTE :: -1
|
||||
// The symbol provides general type or debugging information but does not
|
||||
// correspond to a section. Microsoft tools use this setting along
|
||||
// with .file records (storage class FILE).
|
||||
IMAGE_SYM_DEBUG :: -2
|
||||
|
||||
IMAGE_SYM_TYPE :: enum u16le {
|
||||
NULL = 0,
|
||||
VOID = 1,
|
||||
CHAR = 2,
|
||||
SHORT = 3,
|
||||
INT = 4,
|
||||
LONG = 5,
|
||||
FLOAT = 6,
|
||||
DOUBLE = 7,
|
||||
STRUCT = 8,
|
||||
UNION = 9,
|
||||
ENUM = 10,
|
||||
MOE = 11,
|
||||
BYTE = 12,
|
||||
WORD = 13,
|
||||
UINT = 14,
|
||||
DWORD = 15,
|
||||
PCODE = 32768,
|
||||
|
||||
DTYPE_NULL = 0,
|
||||
DTYPE_POINTER = 0x10,
|
||||
DTYPE_FUNCTION = 0x20,
|
||||
DTYPE_ARRAY = 0x30,
|
||||
}
|
||||
|
||||
IMAGE_SYM_CLASS :: enum u8 {
|
||||
NULL = 0,
|
||||
AUTOMATIC = 1,
|
||||
EXTERNAL = 2,
|
||||
STATIC = 3,
|
||||
REGISTER = 4,
|
||||
EXTERNAL_DEF = 5,
|
||||
LABEL = 6,
|
||||
UNDEFINED_LABEL = 7,
|
||||
MEMBER_OF_STRUCT = 8,
|
||||
ARGUMENT = 9,
|
||||
STRUCT_TAG = 10,
|
||||
MEMBER_OF_UNION = 11,
|
||||
UNION_TAG = 12,
|
||||
TYPE_DEFINITION = 13,
|
||||
UNDEFINED_STATIC = 14,
|
||||
ENUM_TAG = 15,
|
||||
MEMBER_OF_ENUM = 16,
|
||||
REGISTER_PARAM = 17,
|
||||
BIT_FIELD = 18,
|
||||
FAR_EXTERNAL = 68, // Not in PECOFF v8 spec
|
||||
BLOCK = 100,
|
||||
FUNCTION = 101,
|
||||
END_OF_STRUCT = 102,
|
||||
FILE = 103,
|
||||
SECTION = 104,
|
||||
WEAK_EXTERNAL = 105,
|
||||
CLR_TOKEN = 107,
|
||||
|
||||
END_OF_FUNCTION = 255,
|
||||
}
|
||||
@@ -405,7 +405,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
raw_map.entries.allocator = p.allocator
|
||||
}
|
||||
|
||||
header := runtime.__get_map_header_runtime(raw_map, t)
|
||||
header := runtime.__get_map_header_table_runtime(t)
|
||||
|
||||
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
||||
defer delete(elem_backing, p.allocator)
|
||||
@@ -422,19 +422,17 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
delete(key, p.allocator)
|
||||
return err
|
||||
}
|
||||
|
||||
hash := runtime.Map_Hash {
|
||||
hash = runtime.default_hasher_string(&key, 0),
|
||||
key_ptr = &key,
|
||||
}
|
||||
|
||||
|
||||
key_hash := runtime.default_hasher_string(&key, 0)
|
||||
key_ptr := rawptr(&key)
|
||||
|
||||
key_cstr: cstring
|
||||
if reflect.is_cstring(t.key) {
|
||||
key_cstr = cstring(raw_data(key))
|
||||
hash.key_ptr = &key_cstr
|
||||
key_ptr = &key_cstr
|
||||
}
|
||||
|
||||
set_ptr := runtime.__dynamic_map_set(header, hash, map_backing_value.data)
|
||||
set_ptr := runtime.__dynamic_map_set(raw_map, header, key_hash, key_ptr, map_backing_value.data)
|
||||
if set_ptr == nil {
|
||||
delete(key, p.allocator)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
|
||||
} else when N == 2 {
|
||||
out = builtin.max(a[0], a[1])
|
||||
} else when N == 3 {
|
||||
out = builtin.max(a[0], a[1], a[3])
|
||||
out = builtin.max(a[0], a[1], a[2])
|
||||
}else {
|
||||
out = builtin.max(a[0], a[1])
|
||||
for i in 2..<N {
|
||||
|
||||
@@ -120,7 +120,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
|
||||
|
||||
data = make([]byte, int(length), allocator)
|
||||
if data == nil {
|
||||
return nil, false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
bytes_read, read_err := read_full(fd, data)
|
||||
|
||||
@@ -394,7 +394,7 @@ Raw_Dynamic_Array :: struct {
|
||||
}
|
||||
|
||||
Raw_Map :: struct {
|
||||
hashes: []int,
|
||||
hashes: []Map_Index,
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
@@ -289,14 +289,15 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
||||
entries.len = 0
|
||||
for _, i in raw_map.hashes {
|
||||
raw_map.hashes[i] = -1
|
||||
raw_map.hashes[i] = MAP_SENTINEL
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
||||
if m != nil {
|
||||
__dynamic_map_reserve(__get_map_header(m), capacity, loc)
|
||||
h := __get_map_header_table(T)
|
||||
__dynamic_map_reserve(m, h, uint(capacity), loc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,9 +326,8 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
if m != nil {
|
||||
key := key
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
fr := __map_find(h, &key)
|
||||
if fr.entry_index != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
||||
@@ -335,7 +335,6 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -673,11 +672,10 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
||||
@builtin
|
||||
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
||||
key, value := key, value
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
|
||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc))
|
||||
return (^V)(data + h.value_offset)
|
||||
h := __get_map_header_table(T)
|
||||
|
||||
e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
|
||||
return (^V)(uintptr(e) + h.value_offset)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
|
||||
return
|
||||
}
|
||||
|
||||
new_cap := new_cap
|
||||
new_cap = max(new_cap, 0)
|
||||
old_size := array.cap * elem_size
|
||||
new_size := new_cap * elem_size
|
||||
allocator := array.allocator
|
||||
|
||||
@@ -11,38 +11,34 @@ Map_Hash :: struct {
|
||||
key_ptr: rawptr, // address of Map_Entry_Header.key
|
||||
}
|
||||
|
||||
__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) {
|
||||
__get_map_key_hash :: #force_inline proc "contextless" (k: ^$K) -> uintptr {
|
||||
hasher := intrinsics.type_hasher_proc(K)
|
||||
map_hash.key_ptr = k
|
||||
map_hash.hash = hasher(k, 0)
|
||||
return
|
||||
return hasher(k, 0)
|
||||
}
|
||||
|
||||
__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) {
|
||||
hash.hash = entry.hash
|
||||
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
|
||||
return
|
||||
__get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header_Table, entry: ^Map_Entry_Header) -> rawptr {
|
||||
return rawptr(uintptr(entry) + h.key_offset)
|
||||
}
|
||||
|
||||
|
||||
Map_Index :: distinct uint
|
||||
MAP_SENTINEL :: ~Map_Index(0)
|
||||
|
||||
Map_Find_Result :: struct {
|
||||
hash_index: int,
|
||||
entry_prev: int,
|
||||
entry_index: int,
|
||||
hash_index: Map_Index,
|
||||
entry_prev: Map_Index,
|
||||
entry_index: Map_Index,
|
||||
}
|
||||
|
||||
Map_Entry_Header :: struct {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
next: Map_Index,
|
||||
/*
|
||||
key: Key_Value,
|
||||
value: Value_Type,
|
||||
*/
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^Raw_Map,
|
||||
Map_Header_Table :: struct {
|
||||
equal: Equal_Proc,
|
||||
|
||||
entry_size: int,
|
||||
@@ -55,6 +51,102 @@ Map_Header :: struct {
|
||||
value_size: int,
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^Raw_Map,
|
||||
using table: Map_Header_Table,
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_get :: proc "contextless" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr) -> rawptr {
|
||||
if m != nil {
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
index := __dynamic_map_find(h, key_hash, key_ptr).entry_index
|
||||
if index != MAP_SENTINEL {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||
return rawptr(data + h.value_offset)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_set :: proc "odin" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||
add_entry :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, loc := #caller_location) -> Map_Index {
|
||||
prev := Map_Index(h.m.entries.len)
|
||||
c := Map_Index(__dynamic_array_append_nothing(&h.m.entries, h.entry_size, h.entry_align, loc))
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1)
|
||||
end.hash = key_hash
|
||||
mem_copy(rawptr(uintptr(end) + h.key_offset), key_ptr, h.key_size)
|
||||
end.next = MAP_SENTINEL
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
|
||||
index := MAP_SENTINEL
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(m, table, INITIAL_MAP_CAP, loc)
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, key_hash, key_ptr)
|
||||
if fr.entry_index != MAP_SENTINEL {
|
||||
index = fr.entry_index
|
||||
} else {
|
||||
index = add_entry(h, key_hash, key_ptr, loc)
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
entry.next = index
|
||||
} else if fr.hash_index != MAP_SENTINEL {
|
||||
h.m.hashes[fr.hash_index] = index
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(h, index)
|
||||
e.hash = key_hash
|
||||
|
||||
key := rawptr(uintptr(e) + h.key_offset)
|
||||
val := rawptr(uintptr(e) + h.value_offset)
|
||||
|
||||
mem_copy(key, key_ptr, h.key_size)
|
||||
mem_copy(val, value, h.value_size)
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
return __dynamic_map_get_entry(h, index)
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_reserve :: proc "odin" (m: rawptr, table: Map_Header_Table, cap: uint, loc := #caller_location) {
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
|
||||
c := context
|
||||
if h.m.entries.allocator.procedure != nil {
|
||||
c.allocator = h.m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
cap := cap
|
||||
cap = ceil_to_pow2(cap)
|
||||
|
||||
__dynamic_array_reserve(&h.m.entries, h.entry_size, h.entry_align, int(cap), loc)
|
||||
|
||||
if h.m.entries.len*2 < len(h.m.hashes) {
|
||||
return
|
||||
}
|
||||
if __slice_resize(&h.m.hashes, int(cap*2), h.m.entries.allocator, loc) {
|
||||
__dynamic_map_reset_entries(h, loc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INITIAL_HASH_SEED :: 0xcbf29ce484222325
|
||||
|
||||
_fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 {
|
||||
@@ -138,11 +230,22 @@ default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> ui
|
||||
}
|
||||
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^Raw_Map)(m)}
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> (header: Map_Header) {
|
||||
header.m = (^Raw_Map)(m)
|
||||
header.table = #force_inline __get_map_header_table(T)
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> (header: Map_Header) {
|
||||
header.m = m
|
||||
header.table = #force_inline __get_map_header_table_runtime(ti)
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_table :: proc "contextless" ($T: typeid/map[$K]$V) -> (header: Map_Header_Table) {
|
||||
Entry :: struct {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
next: Map_Index,
|
||||
key: K,
|
||||
value: V,
|
||||
}
|
||||
@@ -158,18 +261,16 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header.value_offset = offset_of(Entry, value)
|
||||
header.value_size = size_of(V)
|
||||
|
||||
return header
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> Map_Header {
|
||||
header := Map_Header{m = m}
|
||||
|
||||
__get_map_header_table_runtime :: proc "contextless" (ti: Type_Info_Map) -> (header: Map_Header) {
|
||||
header.equal = ti.key_equal
|
||||
|
||||
|
||||
entries := ti.generated_struct.variant.(Type_Info_Struct).types[1]
|
||||
entry := entries.variant.(Type_Info_Dynamic_Array).elem
|
||||
e := entry.variant.(Type_Info_Struct)
|
||||
|
||||
|
||||
header.entry_size = entry.size
|
||||
header.entry_align = entry.align
|
||||
|
||||
@@ -179,11 +280,12 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map)
|
||||
header.value_offset = e.offsets[3]
|
||||
header.value_size = e.types[3].size
|
||||
|
||||
return header
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||
|
||||
__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||
array := (^Raw_Slice)(array_)
|
||||
|
||||
if new_count < array.len {
|
||||
@@ -205,136 +307,82 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
|
||||
return false
|
||||
}
|
||||
|
||||
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
|
||||
for i in 0..<len(m.hashes) {
|
||||
m.hashes[i] = -1
|
||||
__dynamic_map_reset_entries :: proc "contextless" (h: Map_Header, loc := #caller_location) {
|
||||
for i in 0..<len(h.m.hashes) {
|
||||
h.m.hashes[i] = MAP_SENTINEL
|
||||
}
|
||||
|
||||
for i in 0..<m.entries.len {
|
||||
entry_header := __dynamic_map_get_entry(header, i)
|
||||
entry_hash := __get_map_hash_from_entry(header, entry_header)
|
||||
entry_header.next = -1
|
||||
|
||||
fr := __dynamic_map_find(header, entry_hash)
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = i
|
||||
} else {
|
||||
e := __dynamic_map_get_entry(header, fr.entry_prev)
|
||||
for i in 0..<Map_Index(h.m.entries.len) {
|
||||
entry_header := __dynamic_map_get_entry(h, i)
|
||||
entry_header.next = MAP_SENTINEL
|
||||
|
||||
fr := __dynamic_map_find_from_entry(h, entry_header)
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
e := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
e.next = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
|
||||
c := context
|
||||
if m.entries.allocator.procedure != nil {
|
||||
c.allocator = m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc)
|
||||
|
||||
if m.entries.len*2 < len(m.hashes) {
|
||||
return
|
||||
}
|
||||
if __slice_resize(&m.hashes, cap*2, m.entries.allocator, loc) {
|
||||
__dynamic_map_reset_entries(header, loc)
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_shrink :: proc(using header: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
||||
c := context
|
||||
if m.entries.allocator.procedure != nil {
|
||||
c.allocator = m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc)
|
||||
}
|
||||
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) {
|
||||
#force_inline __dynamic_map_reserve(header, new_count, loc)
|
||||
}
|
||||
|
||||
__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr {
|
||||
index := __dynamic_map_find(h, hash).entry_index
|
||||
if index >= 0 {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||
return rawptr(data + h.value_offset)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||
index: int
|
||||
// assert(value != nil)
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
index = fr.entry_index
|
||||
} else {
|
||||
index = __dynamic_map_add_entry(h, hash, loc)
|
||||
if fr.entry_prev >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
entry.next = index
|
||||
} else if fr.hash_index >= 0 {
|
||||
h.m.hashes[fr.hash_index] = index
|
||||
} else {
|
||||
return nil
|
||||
h.m.hashes[fr.hash_index] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(h, index)
|
||||
e.hash = hash.hash
|
||||
|
||||
key := rawptr(uintptr(e) + h.key_offset)
|
||||
mem_copy(key, hash.key_ptr, h.key_size)
|
||||
|
||||
val := rawptr(uintptr(e) + h.value_offset)
|
||||
mem_copy(val, value, h.value_size)
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc)
|
||||
// index = __dynamic_map_find(h, hash).entry_index
|
||||
// assert(index >= 0)
|
||||
__dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
||||
c := context
|
||||
if h.m.entries.allocator.procedure != nil {
|
||||
c.allocator = h.m.entries.allocator
|
||||
}
|
||||
|
||||
return __dynamic_map_get_entry(h, index)
|
||||
context = c
|
||||
|
||||
return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc)
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
|
||||
// TODO(bill): Determine an efficient growing rate
|
||||
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP)
|
||||
__dynamic_map_rehash(h, new_count, loc)
|
||||
@(private="file")
|
||||
ceil_to_pow2 :: proc "contextless" (n: uint) -> uint {
|
||||
if n <= 2 {
|
||||
return n
|
||||
}
|
||||
n := n
|
||||
n -= 1
|
||||
n |= n >> 1
|
||||
n |= n >> 2
|
||||
n |= n >> 4
|
||||
n |= n >> 8
|
||||
n |= n >> 16
|
||||
when size_of(int) == 8 {
|
||||
n |= n >> 32
|
||||
}
|
||||
n += 1
|
||||
return n
|
||||
}
|
||||
|
||||
__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.len
|
||||
__dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) {
|
||||
new_count := max(uint(h.m.entries.cap) * 2, INITIAL_MAP_CAP)
|
||||
// Rehash through Reserve
|
||||
__dynamic_map_reserve(h.m, h.table, new_count, loc)
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool {
|
||||
return a.hash == b.hash && h.equal(a.key_ptr, b.key_ptr)
|
||||
__dynamic_map_full :: #force_inline proc "contextless" (h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{-1, -1, -1}
|
||||
if n := uintptr(len(m.hashes)); n > 0 {
|
||||
fr.hash_index = int(hash.hash % n)
|
||||
fr.entry_index = m.hashes[fr.hash_index]
|
||||
for fr.entry_index >= 0 {
|
||||
__dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check {
|
||||
key_ptr := __get_map_entry_key_ptr(h, e)
|
||||
return __dynamic_map_find(h, e.hash, key_ptr)
|
||||
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}
|
||||
if n := uintptr(len(h.m.hashes)); n != 0 {
|
||||
fr.hash_index = Map_Index(key_hash & (n-1))
|
||||
fr.entry_index = h.m.hashes[fr.hash_index]
|
||||
for fr.entry_index != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
entry_hash := __get_map_hash_from_entry(h, entry)
|
||||
if __dynamic_map_hash_equal(h, entry_hash, hash) {
|
||||
entry_key_ptr := __get_map_entry_key_ptr(h, entry)
|
||||
if entry.hash == key_hash && h.equal(entry_key_ptr, key_ptr) {
|
||||
return fr
|
||||
}
|
||||
// assert(entry.next < m.entries.len)
|
||||
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = entry.next
|
||||
@@ -343,58 +391,38 @@ __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Resu
|
||||
return fr
|
||||
}
|
||||
|
||||
__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int {
|
||||
prev := m.entries.len
|
||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc)
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1)
|
||||
end.hash = hash.hash
|
||||
mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size)
|
||||
end.next = -1
|
||||
}
|
||||
return prev
|
||||
// Utility procedure used by other runtime procedures
|
||||
__map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check {
|
||||
hash := __get_map_key_hash(key_ptr)
|
||||
return #force_inline __dynamic_map_find(h, hash, key_ptr)
|
||||
}
|
||||
|
||||
__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) {
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
__dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header {
|
||||
return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size)))
|
||||
}
|
||||
|
||||
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
||||
// assert(0 <= index && index < m.entries.len)
|
||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
|
||||
}
|
||||
|
||||
__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) {
|
||||
mem_copy(new, old, h.entry_size)
|
||||
}
|
||||
|
||||
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||
} else {
|
||||
__dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
prev := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
curr := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
prev.next = curr.next
|
||||
}
|
||||
if fr.entry_index == m.entries.len-1 {
|
||||
// NOTE(bill): No need to do anything else, just pop
|
||||
} else {
|
||||
h.m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||
}
|
||||
last_index := Map_Index(h.m.entries.len-1)
|
||||
if fr.entry_index != last_index {
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1)
|
||||
__dynamic_map_copy_entry(h, old, end)
|
||||
end := __dynamic_map_get_entry(h, last_index)
|
||||
mem_copy(old, end, h.entry_size)
|
||||
|
||||
old_hash := __get_map_hash_from_entry(h, old)
|
||||
|
||||
if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev)
|
||||
last_entry.next = fr.entry_index
|
||||
last := __dynamic_map_find_from_entry(h, old)
|
||||
if last.entry_prev != MAP_SENTINEL {
|
||||
e := __dynamic_map_get_entry(h, last.entry_prev)
|
||||
e.next = fr.entry_index
|
||||
} else {
|
||||
m.hashes[last.hash_index] = fr.entry_index
|
||||
h.m.hashes[last.hash_index] = fr.entry_index
|
||||
}
|
||||
}
|
||||
|
||||
m.entries.len -= 1
|
||||
h.m.entries.len -= 1
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import "core:builtin"
|
||||
import "core:mem"
|
||||
|
||||
ptr_add :: proc(p: $P/^$T, x: int) -> ^T {
|
||||
return (^T)(uintptr(p) + size_of(T)*x)
|
||||
return ([^]T)(p)[x:]
|
||||
}
|
||||
ptr_sub :: proc(p: $P/^$T, x: int) -> ^T {
|
||||
return #force_inline ptr_add(p, -x)
|
||||
return ([^]T)(p)[-x:]
|
||||
}
|
||||
|
||||
ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) {
|
||||
@@ -84,12 +84,14 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
||||
mid = ptr_add(mid, left)
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
||||
mid = ptr_add(mid, left)
|
||||
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,3 +509,10 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
|
||||
}
|
||||
return r, true
|
||||
}
|
||||
|
||||
|
||||
// Convert a pointer to an enumerated array to a slice of the element type
|
||||
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
|
||||
where intrinsics.type_is_enumerated_array(T) {
|
||||
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
|
||||
}
|
||||
@@ -820,3 +820,147 @@ foreign kernel32 {
|
||||
|
||||
HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
|
||||
PHANDLER_ROUTINE :: HandlerRoutine
|
||||
|
||||
|
||||
|
||||
|
||||
DCB_Config :: struct {
|
||||
fParity: bool,
|
||||
fOutxCtsFlow: bool,
|
||||
fOutxDsrFlow: bool,
|
||||
fDtrControl: DTR_Control,
|
||||
fDsrSensitivity: bool,
|
||||
fTXContinueOnXoff: bool,
|
||||
fOutX: bool,
|
||||
fInX: bool,
|
||||
fErrorChar: bool,
|
||||
fNull: bool,
|
||||
fRtsControl: RTS_Control,
|
||||
fAbortOnError: bool,
|
||||
BaudRate: DWORD,
|
||||
ByteSize: BYTE,
|
||||
Parity: Parity,
|
||||
StopBits: Stop_Bits,
|
||||
XonChar: byte,
|
||||
XoffChar: byte,
|
||||
ErrorChar: byte,
|
||||
EvtChar: byte,
|
||||
}
|
||||
DTR_Control :: enum byte {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
Handshake = 2,
|
||||
}
|
||||
RTS_Control :: enum byte {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
Handshake = 2,
|
||||
Toggle = 3,
|
||||
}
|
||||
Parity :: enum byte {
|
||||
None = 0,
|
||||
Odd = 1,
|
||||
Even = 2,
|
||||
Mark = 3,
|
||||
Space = 4,
|
||||
}
|
||||
Stop_Bits :: enum byte {
|
||||
One = 0,
|
||||
One_And_A_Half = 1,
|
||||
Two = 2,
|
||||
}
|
||||
|
||||
// A helper procedure to set the values of a DCB structure.
|
||||
init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) {
|
||||
out: u32
|
||||
|
||||
// NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield
|
||||
// appear to be defined from LSB to MSB order.
|
||||
// i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32.
|
||||
|
||||
out |= u32(1) << 0 // fBinary must always be true on Windows.
|
||||
|
||||
out |= u32(config.fParity) << 1
|
||||
out |= u32(config.fOutxCtsFlow) << 2
|
||||
out |= u32(config.fOutxDsrFlow) << 3
|
||||
|
||||
out |= u32(config.fDtrControl) << 4
|
||||
|
||||
out |= u32(config.fDsrSensitivity) << 6
|
||||
out |= u32(config.fTXContinueOnXoff) << 7
|
||||
out |= u32(config.fOutX) << 8
|
||||
out |= u32(config.fInX) << 9
|
||||
out |= u32(config.fErrorChar) << 10
|
||||
out |= u32(config.fNull) << 11
|
||||
|
||||
out |= u32(config.fRtsControl) << 12
|
||||
|
||||
out |= u32(config.fAbortOnError) << 14
|
||||
|
||||
dcb.settings = out
|
||||
|
||||
dcb.BaudRate = config.BaudRate
|
||||
dcb.ByteSize = config.ByteSize
|
||||
dcb.Parity = config.Parity
|
||||
dcb.StopBits = config.StopBits
|
||||
dcb.XonChar = config.XonChar
|
||||
dcb.XoffChar = config.XoffChar
|
||||
dcb.ErrorChar = config.ErrorChar
|
||||
dcb.EvtChar = config.EvtChar
|
||||
|
||||
dcb.DCBlength = size_of(DCB)
|
||||
}
|
||||
get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) {
|
||||
config.fParity = bool((dcb.settings >> 1) & 0x01)
|
||||
config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01)
|
||||
config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01)
|
||||
|
||||
config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02)
|
||||
|
||||
config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01)
|
||||
config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01)
|
||||
config.fOutX = bool((dcb.settings >> 8) & 0x01)
|
||||
config.fInX = bool((dcb.settings >> 9) & 0x01)
|
||||
config.fErrorChar = bool((dcb.settings >> 10) & 0x01)
|
||||
config.fNull = bool((dcb.settings >> 11) & 0x01)
|
||||
|
||||
config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02)
|
||||
|
||||
config.fAbortOnError = bool((dcb.settings >> 14) & 0x01)
|
||||
|
||||
config.BaudRate = dcb.BaudRate
|
||||
config.ByteSize = dcb.ByteSize
|
||||
config.Parity = dcb.Parity
|
||||
config.StopBits = dcb.StopBits
|
||||
config.XonChar = dcb.XonChar
|
||||
config.XoffChar = dcb.XoffChar
|
||||
config.ErrorChar = dcb.ErrorChar
|
||||
config.EvtChar = dcb.EvtChar
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this.
|
||||
DCB :: struct {
|
||||
DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB).
|
||||
BaudRate: DWORD,
|
||||
settings: u32, // NOTE(tetra): These are bitfields in the C struct.
|
||||
wReserved: WORD,
|
||||
XOnLim: WORD,
|
||||
XOffLim: WORD,
|
||||
ByteSize: BYTE,
|
||||
Parity: Parity,
|
||||
StopBits: Stop_Bits,
|
||||
XonChar: byte,
|
||||
XoffChar: byte,
|
||||
ErrorChar: byte,
|
||||
EofChar: byte,
|
||||
EvtChar: byte,
|
||||
wReserved1: WORD,
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||
}
|
||||
@@ -3,22 +3,22 @@ package all
|
||||
// Imports every package
|
||||
// This is useful for knowing what exists and producing documentation with `odin doc`
|
||||
|
||||
import bufio "core:bufio"
|
||||
import bytes "core:bytes"
|
||||
import bufio "core:bufio"
|
||||
import bytes "core:bytes"
|
||||
|
||||
import c "core:c"
|
||||
import libc "core:c/libc"
|
||||
import c "core:c"
|
||||
import libc "core:c/libc"
|
||||
|
||||
import compress "core:compress"
|
||||
import shoco "core:compress/shoco"
|
||||
import gzip "core:compress/gzip"
|
||||
import zlib "core:compress/zlib"
|
||||
import compress "core:compress"
|
||||
import shoco "core:compress/shoco"
|
||||
import gzip "core:compress/gzip"
|
||||
import zlib "core:compress/zlib"
|
||||
|
||||
import bit_array "core:container/bit_array"
|
||||
import priority_queue "core:container/priority_queue"
|
||||
import queue "core:container/queue"
|
||||
import small_array "core:container/small_array"
|
||||
import lru "core:container/lru"
|
||||
import bit_array "core:container/bit_array"
|
||||
import priority_queue "core:container/priority_queue"
|
||||
import queue "core:container/queue"
|
||||
import small_array "core:container/small_array"
|
||||
import lru "core:container/lru"
|
||||
|
||||
import crypto "core:crypto"
|
||||
import blake "core:crypto/blake"
|
||||
@@ -27,7 +27,7 @@ import blake2s "core:crypto/blake2s"
|
||||
import chacha20 "core:crypto/chacha20"
|
||||
import chacha20poly1305 "core:crypto/chacha20poly1305"
|
||||
import gost "core:crypto/gost"
|
||||
import groestl "core:crypto/groestl"
|
||||
import groestl "core:crypto/groestl"
|
||||
import haval "core:crypto/haval"
|
||||
import jh "core:crypto/jh"
|
||||
import keccak "core:crypto/keccak"
|
||||
@@ -48,73 +48,74 @@ import crypto_util "core:crypto/util"
|
||||
import whirlpool "core:crypto/whirlpool"
|
||||
import x25519 "core:crypto/x25519"
|
||||
|
||||
import dynlib "core:dynlib"
|
||||
import dynlib "core:dynlib"
|
||||
|
||||
import base32 "core:encoding/base32"
|
||||
import base64 "core:encoding/base64"
|
||||
import csv "core:encoding/csv"
|
||||
import hxa "core:encoding/hxa"
|
||||
import json "core:encoding/json"
|
||||
import varint "core:encoding/varint"
|
||||
import xml "core:encoding/xml"
|
||||
import base32 "core:encoding/base32"
|
||||
import base64 "core:encoding/base64"
|
||||
import csv "core:encoding/csv"
|
||||
import hxa "core:encoding/hxa"
|
||||
import json "core:encoding/json"
|
||||
import varint "core:encoding/varint"
|
||||
import xml "core:encoding/xml"
|
||||
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
|
||||
import image "core:image"
|
||||
import netpbm "core:image/netpbm"
|
||||
import png "core:image/png"
|
||||
import qoi "core:image/qoi"
|
||||
import tga "core:image/tga"
|
||||
import image "core:image"
|
||||
import netpbm "core:image/netpbm"
|
||||
import png "core:image/png"
|
||||
import qoi "core:image/qoi"
|
||||
import tga "core:image/tga"
|
||||
|
||||
import io "core:io"
|
||||
import log "core:log"
|
||||
import io "core:io"
|
||||
import log "core:log"
|
||||
|
||||
import math "core:math"
|
||||
import big "core:math/big"
|
||||
import bits "core:math/bits"
|
||||
import fixed "core:math/fixed"
|
||||
import linalg "core:math/linalg"
|
||||
import glm "core:math/linalg/glsl"
|
||||
import hlm "core:math/linalg/hlsl"
|
||||
import rand "core:math/rand"
|
||||
import math "core:math"
|
||||
import big "core:math/big"
|
||||
import bits "core:math/bits"
|
||||
import fixed "core:math/fixed"
|
||||
import linalg "core:math/linalg"
|
||||
import glm "core:math/linalg/glsl"
|
||||
import hlm "core:math/linalg/hlsl"
|
||||
import noise "core:math/noise"
|
||||
import rand "core:math/rand"
|
||||
|
||||
import mem "core:mem"
|
||||
import mem "core:mem"
|
||||
// import virtual "core:mem/virtual"
|
||||
|
||||
import ast "core:odin/ast"
|
||||
import doc_format "core:odin/doc-format"
|
||||
import odin_format "core:odin/format"
|
||||
import odin_parser "core:odin/parser"
|
||||
import odin_printer "core:odin/printer"
|
||||
import odin_tokenizer "core:odin/tokenizer"
|
||||
import ast "core:odin/ast"
|
||||
import doc_format "core:odin/doc-format"
|
||||
import odin_format "core:odin/format"
|
||||
import odin_parser "core:odin/parser"
|
||||
import odin_printer "core:odin/printer"
|
||||
import odin_tokenizer "core:odin/tokenizer"
|
||||
|
||||
import os "core:os"
|
||||
import os "core:os"
|
||||
|
||||
import slashpath "core:path/slashpath"
|
||||
import filepath "core:path/filepath"
|
||||
import slashpath "core:path/slashpath"
|
||||
import filepath "core:path/filepath"
|
||||
|
||||
import reflect "core:reflect"
|
||||
import runtime "core:runtime"
|
||||
import simd "core:simd"
|
||||
import slice "core:slice"
|
||||
import slice_heap "core:slice/heap"
|
||||
import sort "core:sort"
|
||||
import strconv "core:strconv"
|
||||
import strings "core:strings"
|
||||
import sync "core:sync"
|
||||
import testing "core:testing"
|
||||
import scanner "core:text/scanner"
|
||||
import i18n "core:text/i18n"
|
||||
import thread "core:thread"
|
||||
import time "core:time"
|
||||
import reflect "core:reflect"
|
||||
import runtime "core:runtime"
|
||||
import simd "core:simd"
|
||||
import slice "core:slice"
|
||||
import slice_heap "core:slice/heap"
|
||||
import sort "core:sort"
|
||||
import strconv "core:strconv"
|
||||
import strings "core:strings"
|
||||
import sync "core:sync"
|
||||
import testing "core:testing"
|
||||
import scanner "core:text/scanner"
|
||||
import i18n "core:text/i18n"
|
||||
import thread "core:thread"
|
||||
import time "core:time"
|
||||
|
||||
import sysinfo "core:sys/info"
|
||||
import sysinfo "core:sys/info"
|
||||
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
import utf16 "core:unicode/utf16"
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
import utf16 "core:unicode/utf16"
|
||||
|
||||
main :: proc(){}
|
||||
|
||||
@@ -183,6 +184,7 @@ _ :: fixed
|
||||
_ :: linalg
|
||||
_ :: glm
|
||||
_ :: hlm
|
||||
_ :: noise
|
||||
_ :: rand
|
||||
_ :: mem
|
||||
_ :: ast
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package all
|
||||
|
||||
import botan "vendor:botan"
|
||||
import ENet "vendor:ENet"
|
||||
import ggpo "vendor:ggpo"
|
||||
import gl "vendor:OpenGL"
|
||||
import glfw "vendor:glfw"
|
||||
import microui "vendor:microui"
|
||||
import miniaudio "vendor:miniaudio"
|
||||
import PM "vendor:portmidi"
|
||||
import rl "vendor:raylib"
|
||||
import exr "vendor:OpenEXRCore"
|
||||
import botan "vendor:botan"
|
||||
import ENet "vendor:ENet"
|
||||
import ggpo "vendor:ggpo"
|
||||
import gl "vendor:OpenGL"
|
||||
import glfw "vendor:glfw"
|
||||
import microui "vendor:microui"
|
||||
import miniaudio "vendor:miniaudio"
|
||||
import PM "vendor:portmidi"
|
||||
import rl "vendor:raylib"
|
||||
import exr "vendor:OpenEXRCore"
|
||||
|
||||
import SDL "vendor:sdl2"
|
||||
import SDLNet "vendor:sdl2/net"
|
||||
import IMG "vendor:sdl2/image"
|
||||
import MIX "vendor:sdl2/mixer"
|
||||
import TTF "vendor:sdl2/ttf"
|
||||
import SDL "vendor:sdl2"
|
||||
import SDLNet "vendor:sdl2/net"
|
||||
import IMG "vendor:sdl2/image"
|
||||
import MIX "vendor:sdl2/mixer"
|
||||
import TTF "vendor:sdl2/ttf"
|
||||
|
||||
import vk "vendor:vulkan"
|
||||
import vk "vendor:vulkan"
|
||||
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
|
||||
_ :: botan
|
||||
_ :: ENet
|
||||
@@ -33,12 +33,15 @@ _ :: miniaudio
|
||||
_ :: PM
|
||||
_ :: rl
|
||||
_ :: exr
|
||||
|
||||
_ :: SDL
|
||||
_ :: SDLNet
|
||||
_ :: IMG
|
||||
_ :: MIX
|
||||
_ :: TTF
|
||||
|
||||
_ :: vk
|
||||
|
||||
_ :: NS
|
||||
_ :: MTL
|
||||
_ :: CA
|
||||
_ :: CA
|
||||
5
examples/all/all_vendor_cmark.odin
Normal file
5
examples/all/all_vendor_cmark.odin
Normal file
@@ -0,0 +1,5 @@
|
||||
//+build windows, linux
|
||||
package all
|
||||
|
||||
import cm "vendor:commonmark"
|
||||
_ :: cm
|
||||
5
examples/all/all_vendor_zlib.odin
Normal file
5
examples/all/all_vendor_zlib.odin
Normal file
@@ -0,0 +1,5 @@
|
||||
//+build windows, linux
|
||||
package all
|
||||
|
||||
import zlib "vendor:zlib"
|
||||
_ :: zlib
|
||||
@@ -986,6 +986,15 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
gb_memmove(str+i, path.text, path.len); i += path.len;
|
||||
str[i] = 0;
|
||||
|
||||
// IMPORTANT NOTE(bill): Remove trailing path separators
|
||||
// this is required to make sure there is a conventional
|
||||
// notation for the path
|
||||
for (/**/; i > 0; i--) {
|
||||
u8 c = str[i-1];
|
||||
if (c != '/' && c != '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String res = make_string(str, i);
|
||||
res = string_trim_whitespace(res);
|
||||
@@ -1302,13 +1311,16 @@ void enable_target_feature(TokenPos pos, String const &target_feature_list) {
|
||||
defer (mutex_unlock(&bc->target_features_mutex));
|
||||
|
||||
auto items = split_by_comma(target_feature_list);
|
||||
array_free(&items);
|
||||
for_array(i, items) {
|
||||
String const &item = items.data[i];
|
||||
if (!check_target_feature_is_valid(pos, item)) {
|
||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||
continue;
|
||||
}
|
||||
|
||||
string_set_add(&bc->target_features_set, item);
|
||||
}
|
||||
array_free(&items);
|
||||
}
|
||||
|
||||
|
||||
@@ -1331,7 +1343,7 @@ char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quot
|
||||
|
||||
if (with_quotes) features[len++] = '"';
|
||||
String feature = build_context.target_features_set.entries[i].value;
|
||||
gb_memmove(features, feature.text, feature.len);
|
||||
gb_memmove(features + len, feature.text, feature.len);
|
||||
len += feature.len;
|
||||
if (with_quotes) features[len++] = '"';
|
||||
}
|
||||
|
||||
@@ -1614,6 +1614,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc_type_info_of:
|
||||
case BuiltinProc_typeid_of:
|
||||
case BuiltinProc_len:
|
||||
case BuiltinProc_cap:
|
||||
case BuiltinProc_min:
|
||||
case BuiltinProc_max:
|
||||
case BuiltinProc_type_is_subtype_of:
|
||||
@@ -1696,16 +1697,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
return check_builtin_procedure_directive(c, operand, call, type_hint);
|
||||
|
||||
case BuiltinProc_len:
|
||||
check_expr_or_type(c, operand, ce->args[0]);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
/* fallthrough */
|
||||
|
||||
case BuiltinProc_cap:
|
||||
{
|
||||
// len :: proc(Type) -> int
|
||||
// cap :: proc(Type) -> int
|
||||
check_expr_or_type(c, operand, ce->args[0]);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *op_type = type_deref(operand->type);
|
||||
Type *type = t_int;
|
||||
@@ -1749,11 +1748,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
mode = Addressing_Value;
|
||||
} else if (is_type_map(op_type)) {
|
||||
mode = Addressing_Value;
|
||||
} else if (operand->mode == Addressing_Type && is_type_enum(op_type) && id == BuiltinProc_len) {
|
||||
} else if (operand->mode == Addressing_Type && is_type_enum(op_type)) {
|
||||
Type *bt = base_type(op_type);
|
||||
mode = Addressing_Constant;
|
||||
value = exact_value_i64(bt->Enum.fields.count);
|
||||
type = t_untyped_integer;
|
||||
mode = Addressing_Constant;
|
||||
type = t_untyped_integer;
|
||||
if (id == BuiltinProc_len) {
|
||||
value = exact_value_i64(bt->Enum.fields.count);
|
||||
} else {
|
||||
GB_ASSERT(id == BuiltinProc_cap);
|
||||
value = exact_value_sub(*bt->Enum.max_value, *bt->Enum.min_value);
|
||||
value = exact_value_increment_one(value);
|
||||
}
|
||||
} else if (is_type_struct(op_type)) {
|
||||
Type *bt = base_type(op_type);
|
||||
if (bt->Struct.soa_kind == StructSoa_Fixed) {
|
||||
@@ -1899,6 +1904,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *bt = base_type(type);
|
||||
if (bt->kind == Type_Struct && bt->Struct.scope != nullptr) {
|
||||
if (is_type_polymorphic(bt)) {
|
||||
gbString t = type_to_string(type);
|
||||
error(field_arg, "Cannot use '%.*s' on an unspecialized polymorphic struct type, got '%s'", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
} else if (bt->Struct.fields.count == 0 && bt->Struct.node == nullptr) {
|
||||
gbString t = type_to_string(type);
|
||||
error(field_arg, "Cannot use '%.*s' on incomplete struct declaration, got '%s'", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(type, field_name, false);
|
||||
if (sel.entity == nullptr) {
|
||||
@@ -3665,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
gb_string_free(xts);
|
||||
}
|
||||
|
||||
Type *type = default_type(x.type);
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = default_type(x.type);
|
||||
operand->type = type;
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// make runtime only for the time being
|
||||
} else if (x.mode == Addressing_Constant && x.value.kind == ExactValue_Integer) {
|
||||
convert_to_typed(c, &x, type);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExactValue res = {};
|
||||
|
||||
i64 sz = type_size_of(x.type);
|
||||
u64 bit_size = sz*8;
|
||||
u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will ne fine
|
||||
u8 *rop = cast(u8 *)rop64;
|
||||
|
||||
size_t max_count = 0;
|
||||
size_t written = 0;
|
||||
size_t size = 1;
|
||||
size_t nails = 0;
|
||||
mp_endian endian = MP_LITTLE_ENDIAN;
|
||||
|
||||
max_count = mp_pack_count(&x.value.value_integer, nails, size);
|
||||
GB_ASSERT(sz >= cast(i64)max_count);
|
||||
|
||||
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||
GB_ASSERT(err == MP_OKAY);
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// TODO(bill): Should this even be allowed at compile time?
|
||||
} else {
|
||||
u64 v = 0;
|
||||
switch (id) {
|
||||
case BuiltinProc_count_ones:
|
||||
case BuiltinProc_count_zeros:
|
||||
switch (sz) {
|
||||
case 1: v = bit_set_count(cast(u32)rop[0]); break;
|
||||
case 2: v = bit_set_count(cast(u32)*(u16 *)rop); break;
|
||||
case 4: v = bit_set_count(*(u32 *)rop); break;
|
||||
case 8: v = bit_set_count(rop64[0]); break;
|
||||
case 16:
|
||||
v += bit_set_count(rop64[0]);
|
||||
v += bit_set_count(rop64[1]);
|
||||
break;
|
||||
default: GB_PANIC("Unhandled sized");
|
||||
}
|
||||
if (id == BuiltinProc_count_zeros) {
|
||||
// flip the result
|
||||
v = bit_size - v;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_trailing_zeros:
|
||||
for (u64 i = 0; i < bit_size; i++) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_leading_zeros:
|
||||
for (u64 i = bit_size-1; i < bit_size; i--) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
res = exact_value_u64(v);
|
||||
}
|
||||
|
||||
if (res.kind != ExactValue_Invalid) {
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1060,6 +1060,8 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
|
||||
type_extra = gb_string_append_fmt(type_extra, " (package %.*s)", LIT(type_pkg->name));
|
||||
}
|
||||
}
|
||||
|
||||
ERROR_BLOCK();
|
||||
error(operand->expr,
|
||||
"Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s",
|
||||
expr_str,
|
||||
@@ -1143,6 +1145,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
|
||||
} else if (source->kind == Type_MultiPointer) {
|
||||
isize level = check_is_assignable_to_using_subtype(source->MultiPointer.elem, poly->Pointer.elem);
|
||||
if (level > 0) {
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->MultiPointer.elem, true, modify_type);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1153,6 +1161,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->MultiPointer.elem, true, modify_type);
|
||||
} else if (source->kind == Type_Pointer) {
|
||||
isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->MultiPointer.elem);
|
||||
if (level > 0) {
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->Pointer.elem, true, modify_type);
|
||||
}
|
||||
return false;
|
||||
case Type_Array:
|
||||
@@ -1348,7 +1362,13 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
if (source->kind == Type_Map) {
|
||||
bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
|
||||
bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
|
||||
return key || value;
|
||||
if (key || value) {
|
||||
poly->Map.entry_type = nullptr;
|
||||
poly->Map.internal_type = nullptr;
|
||||
poly->Map.lookup_result_type = nullptr;
|
||||
init_map_internal_types(poly);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1965,10 +1985,18 @@ void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
} else if (are_types_identical(src, dst)) {
|
||||
} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
|
||||
Type *s = src->DynamicArray.elem;
|
||||
Type *d = dst->Slice.elem;
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
|
||||
error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
|
||||
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
|
||||
error_line("\tSuggestion: a string may be transmuted to %s\n", b);
|
||||
error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n");
|
||||
error_line("\t whereas slices in general are assumed to be mutable.\n");
|
||||
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
|
||||
error_line("\tSuggestion: the expression may be casted to %s\n", b);
|
||||
}
|
||||
@@ -2028,7 +2056,9 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
|
||||
gbString a = expr_to_string(o->expr);
|
||||
gbString b = type_to_string(type);
|
||||
gbString c = type_to_string(o->type);
|
||||
gbString s = exact_value_to_string(o->value);
|
||||
defer(
|
||||
gb_string_free(s);
|
||||
gb_string_free(c);
|
||||
gb_string_free(b);
|
||||
gb_string_free(a);
|
||||
@@ -2037,13 +2067,15 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
|
||||
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s'", a, b);
|
||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||
} else {
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s", a, b, c);
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
} else {
|
||||
error(o->expr, "Cannot convert '%s' to '%s' from '%s", a, b, c);
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
return false;
|
||||
@@ -3904,7 +3936,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
}
|
||||
} else if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' must be an integer", expr_str);
|
||||
gbString type_str = type_to_string(operand.type);
|
||||
error(operand.expr, "Index '%s' must be an integer, got %s", expr_str, type_str);
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(expr_str);
|
||||
if (value) *value = 0;
|
||||
return false;
|
||||
@@ -3914,8 +3948,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) {
|
||||
String idx_str = big_int_to_string(temporary_allocator(), &i);
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value, got %.*s", expr_str, LIT(idx_str));
|
||||
gb_string_free(expr_str);
|
||||
if (value) *value = 0;
|
||||
return false;
|
||||
@@ -3946,7 +3981,7 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
if (out_of_bounds) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
if (lo_str.len > 0) {
|
||||
error(operand.expr, "Index '%s' is out of bounds range %.*s .. %.*s", expr_str, LIT(lo_str), LIT(hi_str));
|
||||
error(operand.expr, "Index '%s' is out of bounds range %.*s ..= %.*s", expr_str, LIT(lo_str), LIT(hi_str));
|
||||
} else {
|
||||
gbString index_type_str = type_to_string(index_type);
|
||||
error(operand.expr, "Index '%s' is out of bounds range of enum type %s", expr_str, index_type_str);
|
||||
@@ -3976,8 +4011,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
}
|
||||
|
||||
if (out_of_bounds) {
|
||||
String idx_str = big_int_to_string(temporary_allocator(), &i);
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
|
||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld, got %.*s", expr_str, max_count, LIT(idx_str));
|
||||
gb_string_free(expr_str);
|
||||
return false;
|
||||
}
|
||||
@@ -4022,6 +4058,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
if (is_type_struct(node->tav.type)) {
|
||||
bool found = false;
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
@@ -4033,9 +4070,14 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
|
||||
defer (array_free(&sub_sel.index));
|
||||
if (sub_sel.index[0] == index) {
|
||||
value = fv->value->tav.value;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Use the zero value if it is not found
|
||||
value = {};
|
||||
}
|
||||
} else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) {
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
@@ -4677,7 +4719,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->value = entity->Constant.value;
|
||||
operand->value = entity->Constant.value;
|
||||
operand->mode = Addressing_Constant;
|
||||
if (operand->value.kind == ExactValue_Procedure) {
|
||||
Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
|
||||
@@ -9064,7 +9106,20 @@ ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_h
|
||||
o->type = t->RelativeSlice.slice_type;
|
||||
if (o->mode != Addressing_Variable) {
|
||||
gbString str = expr_to_string(node);
|
||||
error(node, "Cannot relative slice '%s', value is not addressable", str);
|
||||
error(node, "Cannot relative slice '%s', as value is not addressable", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
{
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString type_str = type_to_string(o->type);
|
||||
error(o->expr, "Cannot slice '%s' of type '%s', as enumerated arrays cannot be sliced", str, type_str);
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
|
||||
@@ -2211,7 +2211,6 @@ void init_map_internal_types(Type *type) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
init_map_entry_type(type);
|
||||
if (type->Map.internal_type != nullptr) return;
|
||||
if (type->Map.generated_struct_type != nullptr) return;
|
||||
|
||||
Type *key = type->Map.key;
|
||||
Type *value = type->Map.value;
|
||||
@@ -2239,7 +2238,6 @@ void init_map_internal_types(Type *type) {
|
||||
generated_struct_type->Struct.fields = fields;
|
||||
type_set_offsets(generated_struct_type);
|
||||
|
||||
type->Map.generated_struct_type = generated_struct_type;
|
||||
type->Map.internal_type = generated_struct_type;
|
||||
type->Map.lookup_result_type = make_optional_ok_type(value);
|
||||
}
|
||||
|
||||
@@ -1922,7 +1922,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
||||
init_map_internal_types(bt);
|
||||
add_type_info_type_internal(c, bt->Map.key);
|
||||
add_type_info_type_internal(c, bt->Map.value);
|
||||
add_type_info_type_internal(c, bt->Map.generated_struct_type);
|
||||
add_type_info_type_internal(c, bt->Map.internal_type);
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -2144,7 +2144,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
init_map_internal_types(bt);
|
||||
add_min_dep_type_info(c, bt->Map.key);
|
||||
add_min_dep_type_info(c, bt->Map.value);
|
||||
add_min_dep_type_info(c, bt->Map.generated_struct_type);
|
||||
add_min_dep_type_info(c, bt->Map.internal_type);
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -2831,23 +2831,12 @@ void init_core_source_code_location(Checker *c) {
|
||||
}
|
||||
|
||||
void init_core_map_type(Checker *c) {
|
||||
if (t_map_hash == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Hash"));
|
||||
if (e->state == EntityState_Unresolved) {
|
||||
check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
|
||||
}
|
||||
t_map_hash = e->type;
|
||||
GB_ASSERT(t_map_hash != nullptr);
|
||||
}
|
||||
|
||||
if (t_map_header == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Header"));
|
||||
if (e->state == EntityState_Unresolved) {
|
||||
check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
|
||||
}
|
||||
t_map_header = e->type;
|
||||
GB_ASSERT(t_map_header != nullptr);
|
||||
if (t_map_hash != nullptr) {
|
||||
return;
|
||||
}
|
||||
t_map_hash = find_core_type(c, str_lit("Map_Hash"));
|
||||
t_map_header = find_core_type(c, str_lit("Map_Header"));
|
||||
t_map_header_table = find_core_type(c, str_lit("Map_Header_Table"));
|
||||
}
|
||||
|
||||
void init_preload(Checker *c) {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include <math.h>
|
||||
|
||||
// TODO(bill): Big numbers
|
||||
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
|
||||
|
||||
gb_global BlockingMutex hash_exact_value_mutex;
|
||||
|
||||
struct Ast;
|
||||
|
||||
@@ -500,52 +500,51 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
|
||||
return value;
|
||||
}
|
||||
|
||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
||||
GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type));
|
||||
lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
|
||||
lbValue lb_gen_map_header_table_internal(lbProcedure *p, Type *map_type) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
map_type = base_type(map_type);
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
|
||||
Type *key_type = map_type->Map.key;
|
||||
Type *val_type = map_type->Map.value;
|
||||
gb_unused(val_type);
|
||||
lbAddr *found = map_get(&m->map_header_table_map, map_type);
|
||||
if (found) {
|
||||
return lb_addr_load(p, *found);
|
||||
}
|
||||
|
||||
GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct);
|
||||
map_type->Map.entry_type->cached_size = -1;
|
||||
map_type->Map.entry_type->Struct.are_offsets_set = false;
|
||||
|
||||
i64 entry_size = type_size_of (map_type->Map.entry_type);
|
||||
i64 entry_align = type_align_of (map_type->Map.entry_type);
|
||||
|
||||
|
||||
i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
|
||||
i64 key_size = type_size_of (map_type->Map.key);
|
||||
|
||||
i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
|
||||
i64 value_size = type_size_of (map_type->Map.value);
|
||||
|
||||
|
||||
Type *map_header_base = base_type(t_map_header);
|
||||
GB_ASSERT(map_header_base->Struct.fields.count == 8);
|
||||
Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type;
|
||||
LLVMValueRef const_values[8] = {};
|
||||
const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type));
|
||||
const_values[1] = lb_get_equal_proc_for_type(p->module, key_type) .value;
|
||||
const_values[2] = lb_const_int(p->module, t_int, entry_size) .value;
|
||||
const_values[3] = lb_const_int(p->module, t_int, entry_align) .value;
|
||||
const_values[4] = lb_const_int(p->module, t_uintptr, key_offset) .value;
|
||||
const_values[5] = lb_const_int(p->module, t_int, key_size) .value;
|
||||
const_values[6] = lb_const_int(p->module, t_uintptr, value_offset).value;
|
||||
const_values[7] = lb_const_int(p->module, t_int, value_size) .value;
|
||||
|
||||
LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values));
|
||||
LLVMBuildStore(p->builder, const_value, h.addr.value);
|
||||
|
||||
// NOTE(bill): Removes unnecessary allocation if split gep
|
||||
lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0);
|
||||
lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
|
||||
lb_emit_store(p, gep0, m);
|
||||
|
||||
return lb_addr_load(p, h);
|
||||
Type *key_type = map_type->Map.key;
|
||||
Type *val_type = map_type->Map.value;
|
||||
gb_unused(val_type);
|
||||
|
||||
Type *st = base_type(t_map_header_table);
|
||||
GB_ASSERT(st->Struct.fields.count == 7);
|
||||
|
||||
LLVMValueRef const_values[7] = {};
|
||||
const_values[0] = lb_get_equal_proc_for_type(m, key_type) .value;
|
||||
const_values[1] = lb_const_int(m, t_int, entry_size) .value;
|
||||
const_values[2] = lb_const_int(m, t_int, entry_align) .value;
|
||||
const_values[3] = lb_const_int(m, t_uintptr, key_offset) .value;
|
||||
const_values[4] = lb_const_int(m, t_int, key_size) .value;
|
||||
const_values[5] = lb_const_int(m, t_uintptr, value_offset).value;
|
||||
const_values[6] = lb_const_int(m, t_int, value_size) .value;
|
||||
|
||||
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_header_table, const_values, gb_count_of(const_values));
|
||||
lbValue res = {llvm_res, t_map_header_table};
|
||||
|
||||
lbAddr addr = lb_add_global_generated(m, t_map_header_table, res, nullptr);
|
||||
lb_make_global_private_const(addr);
|
||||
|
||||
map_set(&m->map_header_table_map, map_type, addr);
|
||||
return lb_addr_load(p, addr);
|
||||
}
|
||||
|
||||
lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||
@@ -595,14 +594,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
||||
lbAddr v = lb_add_local_generated(p, t_map_hash, true);
|
||||
lbValue vp = lb_addr_get_ptr(p, v);
|
||||
key = lb_emit_conv(p, key, key_type);
|
||||
|
||||
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
|
||||
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
|
||||
key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
|
||||
|
||||
if (key_ptr_) *key_ptr_ = key_ptr;
|
||||
|
||||
lbValue hashed_key = lb_const_hash(p->module, key, key_type);
|
||||
if (hashed_key.value == nullptr) {
|
||||
lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
|
||||
@@ -613,32 +610,62 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
||||
hashed_key = lb_emit_call(p, hasher, args);
|
||||
}
|
||||
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr);
|
||||
|
||||
return lb_addr_load(p, v);
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type,
|
||||
lbValue map_key, lbValue map_value, Ast *node) {
|
||||
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) {
|
||||
Type *map_type = base_type(type_deref(map_ptr.type));
|
||||
|
||||
lbValue key_ptr = {};
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, map_type);
|
||||
args[2] = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
|
||||
args[3] = key_ptr;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
|
||||
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
||||
}
|
||||
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type,
|
||||
lbValue const &map_key, lbValue const &map_value, Ast *node) {
|
||||
map_type = base_type(map_type);
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key);
|
||||
lbValue key_ptr = {};
|
||||
lbValue key_hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
|
||||
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
|
||||
|
||||
lbAddr value_addr = lb_add_local_generated(p, v.type, false);
|
||||
lb_addr_store(p, value_addr, v);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
||||
args[3] = lb_emit_source_code_location(p, node);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 6);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, map_type);
|
||||
args[2] = key_hash;
|
||||
args[3] = key_ptr;
|
||||
args[4] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
||||
args[5] = lb_emit_source_code_location(p, node);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_set", args);
|
||||
}
|
||||
|
||||
void lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
|
||||
GB_ASSERT(!build_context.no_dynamic_literals);
|
||||
|
||||
String proc_name = {};
|
||||
if (p->entity) {
|
||||
proc_name = p->entity->token.string;
|
||||
}
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, type_deref(map_ptr.type));
|
||||
args[2] = lb_const_int(p->module, t_int, capacity);
|
||||
args[3] = lb_emit_source_code_location(p, proc_name, pos);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
|
||||
}
|
||||
|
||||
|
||||
struct lbGlobalVariable {
|
||||
lbValue var;
|
||||
@@ -780,6 +807,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
|
||||
var->init = init;
|
||||
} else if (lb_is_const_or_global(init)) {
|
||||
if (!var->is_initialized) {
|
||||
if (is_type_proc(init.type)) {
|
||||
init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
|
||||
}
|
||||
LLVMSetInitializer(var->var.value, init.value);
|
||||
var->is_initialized = true;
|
||||
continue;
|
||||
|
||||
@@ -159,6 +159,8 @@ struct lbModule {
|
||||
|
||||
StringMap<lbAddr> objc_classes;
|
||||
StringMap<lbAddr> objc_selectors;
|
||||
|
||||
PtrMap<Type *, lbAddr> map_header_table_map;
|
||||
};
|
||||
|
||||
struct lbGenerator {
|
||||
@@ -443,9 +445,11 @@ String lb_get_const_string(lbModule *m, lbValue value);
|
||||
|
||||
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
|
||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
|
||||
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||
|
||||
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
|
||||
void lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
|
||||
|
||||
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
||||
lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
|
||||
|
||||
@@ -1423,15 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
switch (rt->kind) {
|
||||
case Type_Map:
|
||||
{
|
||||
lbValue addr = lb_address_from_load_or_generate_local(p, right);
|
||||
lbValue h = lb_gen_map_header(p, addr, rt);
|
||||
lbValue key = lb_gen_map_hash(p, left, rt->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
lbValue map_ptr = lb_address_from_load_or_generate_local(p, right);
|
||||
lbValue key = left;
|
||||
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key);
|
||||
if (be->op.kind == Token_in) {
|
||||
return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||
} else {
|
||||
@@ -3676,16 +3670,14 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
if (is_type_map(t)) {
|
||||
lbAddr map_addr = lb_build_addr(p, ie->expr);
|
||||
lbValue map_val = lb_addr_load(p, map_addr);
|
||||
if (deref) {
|
||||
map_val = lb_emit_load(p, map_val);
|
||||
}
|
||||
|
||||
lbValue key = lb_build_expr(p, ie->index);
|
||||
key = lb_emit_conv(p, key, t->Map.key);
|
||||
|
||||
Type *result_type = type_of_expr(expr);
|
||||
lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val);
|
||||
lbValue map_ptr = lb_addr_get_ptr(p, map_addr);
|
||||
if (is_type_pointer(type_deref(map_ptr.type))) {
|
||||
map_ptr = lb_emit_load(p, map_ptr);
|
||||
}
|
||||
return lb_addr_map(map_ptr, key, t, result_type);
|
||||
}
|
||||
|
||||
@@ -3725,8 +3717,11 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
|
||||
index = lb_const_value(p->module, index_type, idx);
|
||||
} else {
|
||||
index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
|
||||
index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
|
||||
index = lb_emit_arith(p, Token_Sub,
|
||||
lb_build_expr(p, ie->index),
|
||||
lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value),
|
||||
index_type);
|
||||
index = lb_emit_conv(p, index, t_int);
|
||||
}
|
||||
} else {
|
||||
index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
|
||||
@@ -4136,20 +4131,16 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
break;
|
||||
}
|
||||
GB_ASSERT(!build_context.no_dynamic_literals);
|
||||
{
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 3);
|
||||
args[0] = lb_gen_map_header(p, v.addr, type);
|
||||
args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count);
|
||||
args[2] = lb_emit_source_code_location(p, proc_name, pos);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
|
||||
}
|
||||
|
||||
lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
|
||||
|
||||
for_array(field_index, cl->elems) {
|
||||
Ast *elem = cl->elems[field_index];
|
||||
ast_node(fv, FieldValue, elem);
|
||||
|
||||
lbValue key = lb_build_expr(p, fv->field);
|
||||
lbValue value = lb_build_expr(p, fv->value);
|
||||
lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem);
|
||||
lb_insert_dynamic_map_key_and_value(p, v.addr, type, key, value, elem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,9 @@ void lb_init_module(lbModule *m, Checker *c) {
|
||||
|
||||
string_map_init(&m->objc_classes, a);
|
||||
string_map_init(&m->objc_selectors, a);
|
||||
|
||||
map_init(&m->map_header_table_map, a, 0);
|
||||
|
||||
}
|
||||
|
||||
bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
@@ -213,6 +216,17 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
|
||||
}
|
||||
|
||||
|
||||
void lb_make_global_private_const(LLVMValueRef global_data) {
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
}
|
||||
void lb_make_global_private_const(lbAddr const &addr) {
|
||||
lb_make_global_private_const(addr.addr.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This emits a GEP at 0, index
|
||||
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
|
||||
GB_ASSERT(is_type_pointer(value.type));
|
||||
@@ -390,19 +404,8 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||
}
|
||||
|
||||
switch (addr.kind) {
|
||||
case lbAddr_Map: {
|
||||
Type *map_type = base_type(addr.map.type);
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
|
||||
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
||||
}
|
||||
case lbAddr_Map:
|
||||
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||
|
||||
case lbAddr_RelativePointer: {
|
||||
Type *rel_ptr = base_type(lb_addr_type(addr));
|
||||
@@ -711,7 +714,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
|
||||
return;
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||
lb_insert_dynamic_map_key_and_value(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||
return;
|
||||
} else if (addr.kind == lbAddr_Context) {
|
||||
lbAddr old_addr = lb_find_or_generate_context_ptr(p);
|
||||
@@ -926,19 +929,15 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
|
||||
return;
|
||||
} else if (LLVMIsConstant(value.value)) {
|
||||
lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
|
||||
LLVMValueRef global_data = addr.addr.value;
|
||||
// make it truly private data
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
lb_make_global_private_const(addr);
|
||||
|
||||
LLVMValueRef dst_ptr = ptr.value;
|
||||
LLVMValueRef src_ptr = global_data;
|
||||
LLVMValueRef src_ptr = addr.addr.value;
|
||||
src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
|
||||
|
||||
LLVMBuildMemMove(p->builder,
|
||||
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
|
||||
src_ptr, lb_try_get_alignment(global_data, 1),
|
||||
src_ptr, lb_try_get_alignment(src_ptr, 1),
|
||||
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
|
||||
return;
|
||||
}
|
||||
@@ -1059,16 +1058,11 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
|
||||
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
Type *map_type = base_type(addr.map.type);
|
||||
Type *map_type = base_type(type_deref(addr.addr.type));
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||
lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
|
||||
|
||||
@@ -1513,6 +1507,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
|
||||
LLVMTypeRef ret = nullptr;
|
||||
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
|
||||
bool *params_by_ptr = gb_alloc_array(permanent_allocator(), bool, param_count);
|
||||
if (type->Proc.result_count != 0) {
|
||||
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
|
||||
ret = lb_type(m, single_ret);
|
||||
@@ -1538,9 +1533,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
}
|
||||
Type *e_type = reduce_tuple_to_single_type(e->type);
|
||||
|
||||
bool param_is_by_ptr = false;
|
||||
LLVMTypeRef param_type = nullptr;
|
||||
if (e->flags & EntityFlag_ByPtr) {
|
||||
param_type = lb_type(m, alloc_type_pointer(e_type));
|
||||
// it will become a pointer afterwards by making it indirect
|
||||
param_type = lb_type(m, e_type);
|
||||
param_is_by_ptr = true;
|
||||
} else if (is_type_boolean(e_type) &&
|
||||
type_size_of(e_type) <= 1) {
|
||||
param_type = LLVMInt1TypeInContext(m->ctx);
|
||||
@@ -1552,6 +1550,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
}
|
||||
}
|
||||
|
||||
params_by_ptr[param_index] = param_is_by_ptr;
|
||||
params[param_index++] = param_type;
|
||||
}
|
||||
}
|
||||
@@ -1577,6 +1576,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
LLVMPrintTypeToString(ft->ret.type),
|
||||
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
|
||||
}
|
||||
for_array(j, ft->args) {
|
||||
if (params_by_ptr[j]) {
|
||||
// NOTE(bill): The parameter needs to be passed "indirectly", override it
|
||||
ft->args[j].kind = lbArg_Indirect;
|
||||
}
|
||||
}
|
||||
|
||||
map_set(&m->function_type_map, type, ft);
|
||||
LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
|
||||
@@ -2473,10 +2478,8 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
|
||||
string_map_set(&m->const_strings, key, ptr);
|
||||
@@ -2519,10 +2522,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = nullptr;
|
||||
if (str.len != 0) {
|
||||
@@ -2558,10 +2559,8 @@ lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String co
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
i64 data_len = str.len;
|
||||
LLVMValueRef ptr = nullptr;
|
||||
@@ -2669,6 +2668,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
|
||||
GB_ASSERT(type != nullptr);
|
||||
type = default_type(type);
|
||||
|
||||
@@ -121,8 +121,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
p->branch_blocks.allocator = a;
|
||||
p->context_stack.allocator = a;
|
||||
p->scope_stack.allocator = a;
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
|
||||
if (p->is_foreign) {
|
||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||
@@ -379,7 +379,6 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
|
||||
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull");
|
||||
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -577,20 +576,13 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
if (e->token.string != "") {
|
||||
GB_ASSERT(!is_blank_ident(e->token));
|
||||
|
||||
lbAddr res = {};
|
||||
if (return_ptr_value.value != nullptr) {
|
||||
lbValue ptr = return_ptr_value;
|
||||
if (results->variables.count != 1) {
|
||||
ptr = lb_emit_struct_ep(p, ptr, cast(i32)i);
|
||||
}
|
||||
|
||||
res = lb_addr(ptr);
|
||||
lb_add_entity(p->module, e, ptr);
|
||||
lb_add_debug_local_variable(p, ptr.value, e->type, e->token);
|
||||
} else {
|
||||
res = lb_add_local(p, e->type, e);
|
||||
}
|
||||
|
||||
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
|
||||
// This will violate the defer rules if you do:
|
||||
// foo :: proc() -> (x, y: T) {
|
||||
// defer x = ... // defer is executed after the `defer`
|
||||
// return // the values returned should be zeroed
|
||||
// }
|
||||
lbAddr res = lb_add_local(p, e->type, e);
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
||||
lb_addr_store(p, res, c);
|
||||
@@ -893,7 +885,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
GB_ASSERT(param_count-1 <= args.count);
|
||||
param_count -= 1;
|
||||
} else {
|
||||
GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count);
|
||||
GB_ASSERT_MSG(param_count == args.count, "%td == %td (%s)", param_count, args.count, LLVMPrintValueToString(value.value));
|
||||
}
|
||||
|
||||
lbValue result = {};
|
||||
|
||||
@@ -1273,6 +1273,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
|
||||
lbValue parent = lb_build_expr(p, as->rhs[0]);
|
||||
bool is_parent_ptr = is_type_pointer(parent.type);
|
||||
Type *parent_base_type = type_deref(parent.type);
|
||||
|
||||
TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type);
|
||||
GB_ASSERT(switch_kind != TypeSwitch_Invalid);
|
||||
@@ -1288,8 +1289,11 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
lbValue union_data = {};
|
||||
if (switch_kind == TypeSwitch_Union) {
|
||||
union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
|
||||
if (is_type_union_maybe_pointer(type_deref(parent_ptr.type))) {
|
||||
Type *union_type = type_deref(parent_ptr.type);
|
||||
if (is_type_union_maybe_pointer(union_type)) {
|
||||
tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
|
||||
} else if (union_tag_size(union_type) == 0) {
|
||||
tag = {}; // there is no tag for a zero sized union
|
||||
} else {
|
||||
lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
|
||||
tag = lb_emit_load(p, tag_ptr);
|
||||
@@ -1318,8 +1322,15 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(tag.value != nullptr);
|
||||
LLVMValueRef switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||
|
||||
LLVMValueRef switch_instr = nullptr;
|
||||
if (type_size_of(parent_base_type) == 0) {
|
||||
GB_ASSERT(tag.value == nullptr);
|
||||
switch_instr = LLVMBuildSwitch(p->builder, lb_const_bool(p->module, t_llvm_bool, false).value, else_block->block, cast(unsigned)num_cases);
|
||||
} else {
|
||||
GB_ASSERT(tag.value != nullptr);
|
||||
switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||
}
|
||||
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
|
||||
@@ -612,6 +612,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
|
||||
LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
|
||||
LLVMSetInitializer(name_array.value, name_init);
|
||||
LLVMSetInitializer(value_array.value, value_init);
|
||||
LLVMSetGlobalConstant(name_array.value, true);
|
||||
LLVMSetGlobalConstant(value_array.value, true);
|
||||
|
||||
lbValue v_count = lb_const_int(m, t_int, fields.count);
|
||||
|
||||
@@ -787,7 +789,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
|
||||
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
|
||||
init_map_internal_types(t);
|
||||
|
||||
lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
|
||||
lbValue gst = lb_type_info(m, t->Map.internal_type);
|
||||
|
||||
LLVMValueRef vals[5] = {
|
||||
lb_type_info(m, t->Map.key).value,
|
||||
|
||||
@@ -1130,7 +1130,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
case Type_Map:
|
||||
{
|
||||
init_map_internal_types(t);
|
||||
Type *gst = t->Map.generated_struct_type;
|
||||
Type *gst = t->Map.internal_type;
|
||||
switch (index) {
|
||||
case 0: result_type = get_struct_field_type(gst, 0); break;
|
||||
case 1: result_type = get_struct_field_type(gst, 1); break;
|
||||
|
||||
@@ -41,7 +41,6 @@ gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) {
|
||||
|
||||
while (line_end < end) {
|
||||
if (*line_end == '\n') {
|
||||
line_end -= 1;
|
||||
break;
|
||||
}
|
||||
line_end += 1;
|
||||
|
||||
@@ -227,7 +227,6 @@ struct TypeProc {
|
||||
Type *key; \
|
||||
Type *value; \
|
||||
Type *entry_type; \
|
||||
Type *generated_struct_type; \
|
||||
Type *internal_type; \
|
||||
Type *lookup_result_type; \
|
||||
}) \
|
||||
@@ -688,6 +687,7 @@ gb_global Type *t_source_code_location_ptr = nullptr;
|
||||
|
||||
gb_global Type *t_map_hash = nullptr;
|
||||
gb_global Type *t_map_header = nullptr;
|
||||
gb_global Type *t_map_header_table = nullptr;
|
||||
|
||||
|
||||
gb_global Type *t_equal_proc = nullptr;
|
||||
@@ -2107,6 +2107,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
case Type_Pointer:
|
||||
return is_type_polymorphic(t->Pointer.elem, or_specialized);
|
||||
|
||||
case Type_MultiPointer:
|
||||
return is_type_polymorphic(t->MultiPointer.elem, or_specialized);
|
||||
|
||||
case Type_SoaPointer:
|
||||
return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
|
||||
|
||||
@@ -2130,6 +2133,15 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
case Type_Slice:
|
||||
return is_type_polymorphic(t->Slice.elem, or_specialized);
|
||||
|
||||
case Type_Matrix:
|
||||
if (t->Matrix.generic_row_count != nullptr) {
|
||||
return true;
|
||||
}
|
||||
if (t->Matrix.generic_column_count != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return is_type_polymorphic(t->Matrix.elem, or_specialized);
|
||||
|
||||
case Type_Tuple:
|
||||
for_array(i, t->Tuple.variables) {
|
||||
if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
|
||||
@@ -2196,6 +2208,34 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_BitSet:
|
||||
if (is_type_polymorphic(t->BitSet.elem, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
if (t->BitSet.underlying != nullptr &&
|
||||
is_type_polymorphic(t->BitSet.underlying, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_RelativeSlice:
|
||||
if (is_type_polymorphic(t->RelativeSlice.slice_type, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
if (t->RelativeSlice.base_integer != nullptr &&
|
||||
is_type_polymorphic(t->RelativeSlice.base_integer, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Type_RelativePointer:
|
||||
if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
if (t->RelativePointer.base_integer != nullptr &&
|
||||
is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -2,7 +2,7 @@ ODIN=../../odin
|
||||
PYTHON=$(shell which python3)
|
||||
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
||||
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test
|
||||
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test c_libc_test
|
||||
|
||||
download_test_assets:
|
||||
$(PYTHON) download_assets.py
|
||||
@@ -47,4 +47,7 @@ os_exit_test:
|
||||
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
||||
|
||||
i18n_test:
|
||||
$(ODIN) run text/i18n -out:test_core_i18n
|
||||
$(ODIN) run text/i18n -out:test_core_i18n
|
||||
|
||||
c_libc_test:
|
||||
$(ODIN) run c/libc -out:test_core_libc
|
||||
37
tests/core/c/libc/test_core_libc.odin
Normal file
37
tests/core/c/libc/test_core_libc.odin
Normal file
@@ -0,0 +1,37 @@
|
||||
package test_core_libc
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
test_libc_complex(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
91
tests/core/c/libc/test_core_libc_complex_pow.odin
Normal file
91
tests/core/c/libc/test_core_libc_complex_pow.odin
Normal file
@@ -0,0 +1,91 @@
|
||||
package test_core_libc
|
||||
|
||||
import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:c/libc"
|
||||
|
||||
reldiff :: proc(lhs, rhs: $T) -> f64 {
|
||||
if lhs == rhs {
|
||||
return 0.
|
||||
}
|
||||
amean := f64((abs(lhs)+abs(rhs)) / 2.)
|
||||
adiff := f64(abs(lhs - rhs))
|
||||
out := adiff / amean
|
||||
return out
|
||||
}
|
||||
|
||||
isclose :: proc(lhs, rhs: $T, rtol:f64 = 1e-12, atol:f64 = 1e-12) -> bool {
|
||||
adiff := f64(abs(lhs - rhs))
|
||||
if adiff < atol {
|
||||
return true
|
||||
}
|
||||
rdiff := reldiff(lhs, rhs)
|
||||
if rdiff < rtol {
|
||||
return true
|
||||
}
|
||||
fmt.printf("not close -- lhs:%v rhs:%v -- adiff:%e rdiff:%e\n",lhs, rhs, adiff, rdiff)
|
||||
return false
|
||||
}
|
||||
|
||||
// declaring here so they can be used as function pointers
|
||||
|
||||
libc_pow :: proc(x, y: libc.complex_double) -> libc.complex_double {
|
||||
return libc.pow(x,y)
|
||||
}
|
||||
|
||||
libc_powf :: proc(x, y: libc.complex_float) -> libc.complex_float {
|
||||
return libc.pow(x,y)
|
||||
}
|
||||
|
||||
@test
|
||||
test_libc_complex :: proc(t: ^testing.T) {
|
||||
test_libc_pow_binding(t, libc.complex_double, f64, libc_pow, 1e-12, 1e-12)
|
||||
// f32 needs more atol for comparing values close to zero
|
||||
test_libc_pow_binding(t, libc.complex_float, f32, libc_powf, 1e-12, 1e-5)
|
||||
}
|
||||
|
||||
@test
|
||||
test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, pow: proc(LIBC_COMPLEX, LIBC_COMPLEX) -> LIBC_COMPLEX,
|
||||
rtol: f64, atol: f64) {
|
||||
// Tests that c/libc/pow(f) functions have two arguments and that the function works as expected for simple inputs
|
||||
{
|
||||
// tests 2^n
|
||||
expected_real : F = 1./16.
|
||||
expected_imag : F = 0.
|
||||
complex_base := LIBC_COMPLEX(complex(F(2.), F(0.)))
|
||||
for n in -4..=4 {
|
||||
complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
|
||||
result := pow(complex_base, complex_power)
|
||||
expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol))
|
||||
expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol))
|
||||
expected_real *= 2
|
||||
}
|
||||
}
|
||||
{
|
||||
// tests (2i)^n
|
||||
value : F = 1/16.
|
||||
expected_real, expected_imag : F
|
||||
complex_base := LIBC_COMPLEX(complex(F(0.), F(2.)))
|
||||
for n in -4..=4 {
|
||||
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
|
||||
}
|
||||
expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol))
|
||||
expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol))
|
||||
value *= 2
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/OpenGL/constants.odin
vendored
2
vendor/OpenGL/constants.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package odin_gl
|
||||
package vendor_gl
|
||||
|
||||
GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
|
||||
|
||||
|
||||
2
vendor/OpenGL/enums.odin
vendored
2
vendor/OpenGL/enums.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package odin_gl
|
||||
package vendor_gl
|
||||
|
||||
GL_Enum :: enum u64 {
|
||||
FALSE = 0,
|
||||
|
||||
2
vendor/OpenGL/helpers.odin
vendored
2
vendor/OpenGL/helpers.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package odin_gl
|
||||
package vendor_gl
|
||||
|
||||
// Helper for loading shaders into a program
|
||||
|
||||
|
||||
2
vendor/OpenGL/impl.odin
vendored
2
vendor/OpenGL/impl.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package odin_gl
|
||||
package vendor_gl
|
||||
|
||||
loaded_up_to: [2]int
|
||||
loaded_up_to_major := 0
|
||||
|
||||
2
vendor/OpenGL/wrappers.odin
vendored
2
vendor/OpenGL/wrappers.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package odin_gl
|
||||
package vendor_gl
|
||||
|
||||
#assert(size_of(bool) == size_of(u8))
|
||||
|
||||
|
||||
9
vendor/README.md
vendored
9
vendor/README.md
vendored
@@ -141,4 +141,11 @@ Includes full bindings as well as wrappers to match the `core:crypto` API.
|
||||
[CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
|
||||
|
||||
See also LICENSE in the `commonmark` directory itself.
|
||||
Includes full bindings and Windows `.lib` and `.dll`.
|
||||
Includes full bindings and Windows `.lib` and `.dll`.
|
||||
|
||||
## CommonMark
|
||||
|
||||
[zlib](https://github.com/madler/zlib) data compression library
|
||||
|
||||
See also LICENSE in the `zlib` directory itself.
|
||||
Includes full bindings.
|
||||
2
vendor/botan/bindings/botan.odin
vendored
2
vendor/botan/bindings/botan.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package botan_bindings
|
||||
package vendor_botan
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/blake2b/blake2b.odin
vendored
2
vendor/botan/blake2b/blake2b.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package botan_blake2b
|
||||
package vendor_botan_blake2b
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/gost/gost.odin
vendored
2
vendor/botan/gost/gost.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package gost
|
||||
package vendor_gost
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/keccak/keccak.odin
vendored
2
vendor/botan/keccak/keccak.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package keccak
|
||||
package vendor_keccak
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/md4/md4.odin
vendored
2
vendor/botan/md4/md4.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package md4
|
||||
package vendor_md4
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/md5/md5.odin
vendored
2
vendor/botan/md5/md5.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package md5
|
||||
package vendor_md5
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/ripemd/ripemd.odin
vendored
2
vendor/botan/ripemd/ripemd.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package ripemd
|
||||
package vendor_ripemd
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/sha1/sha1.odin
vendored
2
vendor/botan/sha1/sha1.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package sha1
|
||||
package vendor_sha1
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/sha2/sha2.odin
vendored
2
vendor/botan/sha2/sha2.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package sha2
|
||||
package vendor_sha2
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/sha3/sha3.odin
vendored
2
vendor/botan/sha3/sha3.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package sha3
|
||||
package vendor_sha3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/shake/shake.odin
vendored
2
vendor/botan/shake/shake.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package shake
|
||||
package vendor_shake
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/siphash/siphash.odin
vendored
2
vendor/botan/siphash/siphash.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package siphash
|
||||
package vendor_siphash
|
||||
|
||||
/*
|
||||
Copyright 2022 zhibog
|
||||
|
||||
2
vendor/botan/skein512/skein512.odin
vendored
2
vendor/botan/skein512/skein512.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package skein512
|
||||
package vendor_skein512
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/sm3/sm3.odin
vendored
2
vendor/botan/sm3/sm3.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package sm3
|
||||
package vendor_sm3
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/streebog/streebog.odin
vendored
2
vendor/botan/streebog/streebog.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package streebog
|
||||
package vendor_streebog
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/tiger/tiger.odin
vendored
2
vendor/botan/tiger/tiger.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package tiger
|
||||
package vendor_tiger
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/botan/whirlpool/whirlpool.odin
vendored
2
vendor/botan/whirlpool/whirlpool.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package whirlpool
|
||||
package vendor_whirlpool
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
|
||||
2
vendor/commonmark/cmark.odin
vendored
2
vendor/commonmark/cmark.odin
vendored
@@ -4,7 +4,7 @@
|
||||
Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
|
||||
See LICENSE for license details.
|
||||
*/
|
||||
package commonmark
|
||||
package vendor_commonmark
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
2
vendor/commonmark/doc.odin
vendored
2
vendor/commonmark/doc.odin
vendored
@@ -5,7 +5,7 @@
|
||||
Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
|
||||
See LICENSE for license details.
|
||||
*/
|
||||
package commonmark
|
||||
package vendor_commonmark
|
||||
|
||||
/*
|
||||
Parsing - Simple interface:
|
||||
|
||||
2
vendor/ggpo/ggpo.odin
vendored
2
vendor/ggpo/ggpo.odin
vendored
@@ -1,4 +1,4 @@
|
||||
package ggpo
|
||||
package vendor_ggpo
|
||||
|
||||
foreign import lib "GGPO.lib"
|
||||
|
||||
|
||||
2
vendor/stb/image/stb_image.odin
vendored
2
vendor/stb/image/stb_image.odin
vendored
@@ -6,7 +6,7 @@ import c "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" }
|
||||
when ODIN_OS == .Linux { foreign import stbi "../lib/stb_image.a" }
|
||||
when ODIN_OS == .Darwin { foreign import stbi "../lib/stb_image.a" }
|
||||
when ODIN_OS == .Darwin { foreign import stbi "../lib/darwin/stb_image.a" }
|
||||
|
||||
#assert(size_of(b32) == size_of(c.int))
|
||||
|
||||
|
||||
2
vendor/stb/image/stb_image_resize.odin
vendored
2
vendor/stb/image/stb_image_resize.odin
vendored
@@ -4,7 +4,7 @@ import c "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" }
|
||||
when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_resize.a" }
|
||||
when ODIN_OS == .Darwin { foreign import lib "../lib/stb_image_resize.a" }
|
||||
when ODIN_OS == .Darwin { foreign import lib "../lib/darwin/stb_image_resize.a" }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
2
vendor/stb/image/stb_image_write.odin
vendored
2
vendor/stb/image/stb_image_write.odin
vendored
@@ -4,7 +4,7 @@ import c "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" }
|
||||
when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" }
|
||||
when ODIN_OS == .Darwin { foreign import stbiw "../lib/stb_image_write.a" }
|
||||
when ODIN_OS == .Darwin { foreign import stbiw "../lib/darwin/stb_image_write.a" }
|
||||
|
||||
|
||||
write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)
|
||||
|
||||
20
vendor/zlib/LICENSE
vendored
Normal file
20
vendor/zlib/LICENSE
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
(C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
jloup@gzip.org madler@alumni.caltech.edu
|
||||
BIN
vendor/zlib/libz.lib
vendored
Normal file
BIN
vendor/zlib/libz.lib
vendored
Normal file
Binary file not shown.
262
vendor/zlib/zlib.odin
vendored
Normal file
262
vendor/zlib/zlib.odin
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
package vendor_zlib
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Windows { foreign import zlib "libz.lib" }
|
||||
when ODIN_OS == .Linux { foreign import zlib "system:z" }
|
||||
|
||||
VERSION :: "1.2.12"
|
||||
VERNUM :: 0x12c0
|
||||
VER_MAJOR :: 1
|
||||
VER_MINOR :: 2
|
||||
VER_REVISION :: 12
|
||||
VER_SUBREVISION :: 0
|
||||
|
||||
voidp :: rawptr
|
||||
voidpf :: rawptr
|
||||
voidpc :: rawptr
|
||||
Byte :: c.uchar
|
||||
Bytef :: c.uchar
|
||||
uInt :: c.uint
|
||||
uIntf :: c.uint
|
||||
uLong :: c.ulong
|
||||
uLongf :: c.ulong
|
||||
size_t :: c.size_t
|
||||
off_t :: c.long
|
||||
off64_t :: i64
|
||||
crc_t :: u32
|
||||
|
||||
alloc_func :: proc "c" (opaque: voidp, items: uInt, size: uInt) -> voidpf
|
||||
free_func :: proc "c" (opaque: voidp, address: voidpf)
|
||||
|
||||
in_func :: proc "c" (rawptr, [^][^]c.uchar) -> c.uint
|
||||
out_func :: proc "c" (rawptr, [^]c.uchar, c.uint) -> c.int
|
||||
|
||||
gzFile_s :: struct {
|
||||
have: c.uint,
|
||||
next: [^]c.uchar,
|
||||
pos: off64_t,
|
||||
}
|
||||
|
||||
gzFile :: ^gzFile_s
|
||||
|
||||
z_stream_s :: struct {
|
||||
next_in: ^Bytef,
|
||||
avail_in: uInt,
|
||||
total_in: uLong,
|
||||
next_out: ^Bytef,
|
||||
avail_out: uInt,
|
||||
total_out: uLong,
|
||||
msg: [^]c.char,
|
||||
state: rawptr,
|
||||
zalloc: alloc_func,
|
||||
zfree: free_func,
|
||||
opaque: voidpf,
|
||||
data_type: c.int,
|
||||
adler: uLong,
|
||||
reserved: uLong,
|
||||
}
|
||||
|
||||
z_stream :: z_stream_s
|
||||
z_streamp :: ^z_stream
|
||||
|
||||
gz_header_s :: struct {
|
||||
text: c.int,
|
||||
time: uLong,
|
||||
xflags: c.int,
|
||||
os: c.int,
|
||||
extra: [^]Bytef,
|
||||
extra_len: uInt,
|
||||
extra_max: uInt,
|
||||
name: [^]Bytef,
|
||||
name_max: uInt,
|
||||
comment: [^]Bytef,
|
||||
comm_max: uInt,
|
||||
hcrc: c.int,
|
||||
done: c.int,
|
||||
}
|
||||
|
||||
gz_header :: gz_header_s
|
||||
gz_headerp :: ^gz_header
|
||||
|
||||
// Allowed flush values; see deflate() and inflate() below for details
|
||||
NO_FLUSH :: 0
|
||||
PARTIAL_FLUSH :: 1
|
||||
SYNC_FLUSH :: 2
|
||||
FULL_FLUSH :: 3
|
||||
FINISH :: 4
|
||||
BLOCK :: 5
|
||||
TREES :: 6
|
||||
|
||||
// Return codes for the compression/decompression functions. Negative values are
|
||||
// errors, positive values are used for special but normal events.
|
||||
OK :: 0
|
||||
STREAM_END :: 1
|
||||
NEED_DICT :: 2
|
||||
ERRNO :: -1
|
||||
STREAM_ERROR :: -2
|
||||
DATA_ERROR :: -3
|
||||
MEM_ERROR :: -4
|
||||
BUF_ERROR :: -5
|
||||
VERSION_ERROR :: -6
|
||||
|
||||
// compression levels
|
||||
NO_COMPRESSION :: 0
|
||||
BEST_SPEED :: 1
|
||||
BEST_COMPRESSION :: 9
|
||||
DEFAULT_COMPRESSION :: -1
|
||||
|
||||
// compression strategy; see deflateInit2() below for details
|
||||
FILTERED :: 1
|
||||
HUFFMAN_ONLY :: 2
|
||||
RLE :: 3
|
||||
FIXED :: 4
|
||||
DEFAULT_STRATEGY :: 0
|
||||
|
||||
// Possible values of the data_type field for deflate()
|
||||
BINARY :: 0
|
||||
TEXT :: 1
|
||||
ASCII :: TEXT // for compatibility with 1.2.2 and earlier
|
||||
UNKNOWN :: 2
|
||||
|
||||
// The deflate compression method (the only one supported in this version)
|
||||
DEFLATED :: 8
|
||||
|
||||
NULL :: 0 // for initializing zalloc, zfree, opaque
|
||||
|
||||
version :: Version // for compatibility with versions < 1.0.2
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign zlib {
|
||||
// becase zlib.zlibVersion would be silly to write
|
||||
@(link_prefix="zlib")
|
||||
Version :: proc() -> cstring ---
|
||||
|
||||
deflate :: proc(strm: z_streamp, flush: c.int) -> c.int ---
|
||||
deflateEnd :: proc(strm: z_streamp) -> c.int ---
|
||||
inflate :: proc(strm: z_streamp, flush: c.int) -> c.int ---
|
||||
inflateEnd :: proc(strm: z_streamp) -> c.int ---
|
||||
deflateSetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: uInt) -> c.int ---
|
||||
deflateGetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: ^uInt) -> c.int ---
|
||||
deflateCopy :: proc(dest, source: z_streamp) -> c.int ---
|
||||
deflateReset :: proc(strm: z_streamp) -> c.int ---
|
||||
deflateParams :: proc(strm: z_streamp, level, strategy: c.int) -> c.int ---
|
||||
deflateTune :: proc(strm: z_streamp, good_length, max_lazy, nice_length, max_chain: c.int) -> c.int ---
|
||||
deflateBound :: proc(strm: z_streamp, sourceLen: uLong) -> uLong ---
|
||||
deflatePending :: proc(strm: z_streamp, pending: [^]c.uint, bits: [^]c.int) -> c.int ---
|
||||
deflatePrime :: proc(strm: z_streamp, bits, value: c.int) -> c.int ---
|
||||
deflateSetHeader :: proc(strm: z_streamp, head: gz_headerp) -> c.int ---
|
||||
inflateSetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: uInt) -> c.int ---
|
||||
inflateGetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: ^uInt) -> c.int ---
|
||||
inflateSync :: proc(strm: z_streamp) -> c.int ---
|
||||
inflateCopy :: proc(dest, source: z_streamp) -> c.int ---
|
||||
inflateReset :: proc(strm: z_streamp) -> c.int ---
|
||||
inflateReset2 :: proc(strm: z_streamp, windowBits: c.int) -> c.int ---
|
||||
inflatePrime :: proc(strm: z_streamp, bits, value: c.int) -> c.int ---
|
||||
inflateMark :: proc(strm: z_streamp) -> c.long ---
|
||||
inflateGetHeader :: proc(strm: z_streamp, head: gz_headerp) -> c.int ---
|
||||
inflateBack :: proc(strm: z_streamp, _in: in_func, in_desc: rawptr, out: out_func, out_desc: rawptr) -> c.int ---
|
||||
inflateBackEnd :: proc(strm: z_streamp) -> c.int ---
|
||||
zlibCompileFlags :: proc() -> uLong ---
|
||||
compress :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong) -> c.int ---
|
||||
compress2 :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong, level: c.int) -> c.int ---
|
||||
compressBound :: proc(sourceLen: uLong) -> uLong ---
|
||||
uncompress :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong) -> c.int ---
|
||||
uncompress2 :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: ^uLong) -> c.int ---
|
||||
gzdopen :: proc(fd: c.int, mode: cstring) -> gzFile ---
|
||||
gzbuffer :: proc(file: gzFile, size: c.uint) -> c.int ---
|
||||
gzsetparams :: proc(file: gzFile, level, strategy: c.int) -> c.int ---
|
||||
gzread :: proc(file: gzFile, buf: voidp, len: c.uint) -> c.int ---
|
||||
gzfread :: proc(buf: voidp, size, nitems: size_t, file: gzFile) -> size_t ---
|
||||
gzwrite :: proc(file: gzFile, buf: voidpc, len: c.uint) -> c.int ---
|
||||
gzfwrite :: proc(buf: voidpc, size, nitems: size_t, file: gzFile) -> size_t ---
|
||||
gzprintf :: proc(file: gzFile, format: cstring, #c_vararg args: ..any) -> c.int ---
|
||||
gzputs :: proc(file: gzFile, s: cstring) -> c.int ---
|
||||
gzgets :: proc(file: gzFile, buf: [^]c.char, len: c.int) -> [^]c.char ---
|
||||
gzputc :: proc(file: gzFile, ch: c.int) -> c.int ---
|
||||
gzgetc_ :: proc(file: gzFile) -> c.int --- // backwards compat, not the same as gzget
|
||||
gzungetc :: proc(ch: c.int, file: gzFile) -> c.int ---
|
||||
gzflush :: proc(file: gzFile, flush: c.int) -> c.int ---
|
||||
gzrewind :: proc(file: gzFile) -> c.int ---
|
||||
gzeof :: proc(file: gzFile) -> c.int ---
|
||||
gzdirect :: proc(file: gzFile) -> c.int ---
|
||||
gzclose :: proc(file: gzFile) -> c.int ---
|
||||
gzclose_r :: proc(file: gzFile) -> c.int ---
|
||||
gzclose_w :: proc(file: gzFile) -> c.int ---
|
||||
gzerror :: proc(file: gzFile, errnum: ^c.int) -> cstring ---
|
||||
gzclearerr :: proc(file: gzFile) ---
|
||||
adler32 :: proc(adler: uLong, buf: [^]Bytef, len: uInt) -> uLong ---
|
||||
adler32_z :: proc(adler: uLong, buf: [^]Bytef, len: size_t) -> uLong ---
|
||||
crc32 :: proc(crc: uLong, buf: [^]Bytef, len: uInt) -> uLong ---
|
||||
crc32_z :: proc(crc: uLong, buf: [^]Bytef, len: size_t) -> uLong ---
|
||||
crc32_combine_op :: proc(crc1, crc2, op: uLong) -> uLong ---
|
||||
gzopen64 :: proc(cstring, cstring) -> gzFile ---
|
||||
gzseek64 :: proc(gzFile, off64_t, c.int) -> off64_t ---
|
||||
gztell64 :: proc(gzFile) -> off64_t ---
|
||||
gzoffset64 :: proc(gzFile) -> off64_t ---
|
||||
adler32_combine64 :: proc(uLong, uLong, off64_t) -> uLong ---
|
||||
crc32_combine64 :: proc(uLong, uLong, off64_t) -> uLong ---
|
||||
crc32_combine_gen64 :: proc(off64_t) -> uLong ---
|
||||
adler32_combine :: proc(uLong, uLong, off_t) -> uLong ---
|
||||
crc32_combine :: proc(uLong, uLong, off_t) -> uLong ---
|
||||
crc32_combine_gen :: proc(off_t) -> uLong ---
|
||||
zError :: proc(c.int) -> cstring ---
|
||||
inflateSyncPoint :: proc(z_streamp) -> c.int ---
|
||||
get_crc_table :: proc() -> [^]crc_t ---
|
||||
inflateUndermine :: proc(z_streamp, c.int) -> c.int ---
|
||||
inflateValidate :: proc(z_streamp, c.int) -> c.int ---
|
||||
inflateCodesUsed :: proc(z_streamp) -> c.ulong ---
|
||||
inflateResetKeep :: proc(z_streamp) -> c.int ---
|
||||
deflateResetKeep :: proc(z_streamp) -> c.int ---
|
||||
}
|
||||
|
||||
// Make these private since we create wrappers below passing in version and size
|
||||
// of the stream structure like zlib.h does
|
||||
@(private)
|
||||
@(default_calling_convention="c")
|
||||
foreign zlib {
|
||||
deflateInit_ :: proc(strm: z_streamp, level: c.int, version: cstring, stream_size: c.int) -> c.int ---
|
||||
inflateInit_ :: proc(strm: z_streamp, level: c.int, version: cstring, stream_size: c.int) -> c.int ---
|
||||
deflateInit2_ :: proc(strm: z_streamp, level, method, windowBits, memLevel, strategy: c.int, version: cstring, stream_size: c.int) -> c.int ---
|
||||
inflateInit2_ :: proc(strm: z_streamp, windowBits: c.int, version: cstring, stream_size: c.int) -> c.int ---
|
||||
inflateBackInit_ :: proc(strm: z_streamp, windowBits: c.int, window: [^]c.uchar, version: cstring, stream_size: c.int) -> c.int ---
|
||||
|
||||
// see below for explanation
|
||||
@(link_name="gzgetc")
|
||||
gzgetc_unique :: proc(file: gzFile) -> c.int ---
|
||||
}
|
||||
|
||||
deflateInit :: #force_inline proc "c" (strm: z_streamp, level: c.int) -> c.int {
|
||||
return deflateInit_(strm, level, VERSION, c.int(size_of(z_stream)))
|
||||
}
|
||||
|
||||
inflateInit :: #force_inline proc "c" (strm: z_streamp, level: c.int) -> c.int {
|
||||
return inflateInit_(strm, level, VERSION, c.int(size_of(z_stream)))
|
||||
}
|
||||
|
||||
deflateInit2 :: #force_inline proc "c" (strm: z_streamp, level, method, windowBits, memLevel, strategy: c.int) -> c.int {
|
||||
return deflateInit2_(strm, level, method, windowBits, memLevel, strategy, VERSION, c.int(size_of(z_stream)))
|
||||
}
|
||||
|
||||
inflateInit2 :: #force_inline proc "c" (strm: z_streamp, windowBits: c.int) -> c.int {
|
||||
return inflateInit2_(strm, windowBits, VERSION, c.int(size_of(z_stream)))
|
||||
}
|
||||
|
||||
inflateBackInit :: #force_inline proc "c" (strm: z_streamp, windowBits: c.int, window: [^]c.uchar) -> c.int {
|
||||
return inflateBackInit_(strm, windowBits, window, VERSION, c.int(size_of(z_stream)))
|
||||
}
|
||||
|
||||
// zlib.h redefines gzgetc with a macro and uses (gzgetc)(g) to invoke it from
|
||||
// inside the same macro (preventing macro expansion), in Odin we give that a
|
||||
// unique name using link_prefix then implement the body of the macro in our own
|
||||
// procedure calling the unique named gzgetc instead.
|
||||
gzgetc :: #force_inline proc(file: gzFile) -> c.int {
|
||||
if file.have != 0 {
|
||||
file.have -= 1
|
||||
file.pos += 1
|
||||
ch := c.int(file.next[0])
|
||||
file.next = &file.next[1]
|
||||
return ch
|
||||
}
|
||||
return gzgetc_unique(file)
|
||||
}
|
||||
Reference in New Issue
Block a user