mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
+3
-49
@@ -1811,7 +1811,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if info.maybe && len(info.variants) == 1 && reflect.is_pointer(info.variants[0]) {
|
if reflect.type_info_union_is_pure_maybe(info) {
|
||||||
if v.data == nil {
|
if v.data == nil {
|
||||||
strings.write_string(fi.buf, "nil");
|
strings.write_string(fi.buf, "nil");
|
||||||
} else {
|
} else {
|
||||||
@@ -1877,59 +1877,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
fmt_opaque(fi, v);
|
fmt_opaque(fi, v);
|
||||||
|
|
||||||
case runtime.Type_Info_Relative_Pointer:
|
case runtime.Type_Info_Relative_Pointer:
|
||||||
ptr_any := any{v.data, info.base_integer.id};
|
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id);
|
||||||
ptr: rawptr;
|
|
||||||
switch i in &ptr_any {
|
|
||||||
case u8: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64: ptr = handle_relative_pointer(&i);
|
|
||||||
case i8: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16be: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32be: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64be: ptr = handle_relative_pointer(&i);
|
|
||||||
}
|
|
||||||
absolute_ptr := any{ptr, info.pointer.id};
|
absolute_ptr := any{ptr, info.pointer.id};
|
||||||
|
|
||||||
fmt_value(fi, absolute_ptr, verb);
|
fmt_value(fi, absolute_ptr, verb);
|
||||||
|
|
||||||
case runtime.Type_Info_Relative_Slice:
|
case runtime.Type_Info_Relative_Slice:
|
||||||
ptr_any := any{v.data, info.base_integer.id};
|
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id);
|
||||||
ptr: rawptr;
|
|
||||||
switch i in &ptr_any {
|
|
||||||
case u8: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64: ptr = handle_relative_pointer(&i);
|
|
||||||
case i8: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32le: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64le: ptr = handle_relative_pointer(&i);
|
|
||||||
case u16be: ptr = handle_relative_pointer(&i);
|
|
||||||
case u32be: ptr = handle_relative_pointer(&i);
|
|
||||||
case u64be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i16be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i32be: ptr = handle_relative_pointer(&i);
|
|
||||||
case i64be: ptr = handle_relative_pointer(&i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if verb == 'p' {
|
if verb == 'p' {
|
||||||
fmt_pointer(fi, ptr, 'p');
|
fmt_pointer(fi, ptr, 'p');
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import win32 "core:sys/windows"
|
|||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
read_dir :: proc(fd: Handle, n: int) -> (fi: []File_Info, err: Errno) {
|
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||||
find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
|
find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
|
||||||
// Ignore "." and ".."
|
// Ignore "." and ".."
|
||||||
if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
|
if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
|
||||||
@@ -53,6 +53,8 @@ read_dir :: proc(fd: Handle, n: int) -> (fi: []File_Info, err: Errno) {
|
|||||||
return nil, ERROR_INVALID_HANDLE;
|
return nil, ERROR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
h := win32.HANDLE(fd);
|
h := win32.HANDLE(fd);
|
||||||
|
|
||||||
dir_fi, _ := stat_from_file_information("", h);
|
dir_fi, _ := stat_from_file_information("", h);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// The path/filepath package uses either forward slashes or backslashes depending on the operating system
|
||||||
|
// To process paths usch as URLs that depend on forward slashes regardless of the OS, use the path package
|
||||||
package filepath
|
package filepath
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|||||||
+12
-147
@@ -1,3 +1,8 @@
|
|||||||
|
// The path package is only to be used for paths separated by forward slashes,
|
||||||
|
// e.g. paths in URLs
|
||||||
|
//
|
||||||
|
// This package does not deal with Windows/NT paths with volume letters or backslashes
|
||||||
|
// To manipulate operating system specific paths, use the path/filepath package
|
||||||
package path
|
package path
|
||||||
|
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
@@ -5,29 +10,14 @@ import "core:runtime"
|
|||||||
import "core:unicode/utf8"
|
import "core:unicode/utf8"
|
||||||
|
|
||||||
// is_separator checks whether the byte is a valid separator character
|
// is_separator checks whether the byte is a valid separator character
|
||||||
is_separator :: proc(c: byte) -> bool {
|
is_separator :: inline proc(c: byte) -> bool {
|
||||||
switch c {
|
return c == '/';
|
||||||
case '/': return true;
|
|
||||||
case '\\': return ODIN_OS == "windows";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// is_abs checks whether the path is absolute
|
// is_abs checks whether the path is absolute
|
||||||
is_abs :: proc(path: string) -> bool {
|
is_abs :: inline proc(path: string) -> bool {
|
||||||
if len(path) > 0 && path[0] == '/' {
|
return len(path) > 0 && path[0] == '/';
|
||||||
return true;
|
|
||||||
}
|
|
||||||
when ODIN_OS == "windows" {
|
|
||||||
if len(path) > 2 {
|
|
||||||
switch path[0] {
|
|
||||||
case 'A'..'Z', 'a'..'z':
|
|
||||||
return path[1] == ':' && is_separator(path[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +41,7 @@ base :: proc(path: string, new := false, allocator := context.allocator) -> (las
|
|||||||
for len(path) > 0 && is_separator(path[len(path)-1]) {
|
for len(path) > 0 && is_separator(path[len(path)-1]) {
|
||||||
path = path[:len(path)-1];
|
path = path[:len(path)-1];
|
||||||
}
|
}
|
||||||
if i := strings.last_index_any(path, OS_SEPARATORS); i >= 0 {
|
if i := strings.last_index(path, "/"); i >= 0 {
|
||||||
path = path[i+1:];
|
path = path[i+1:];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,13 +69,13 @@ dir :: proc(path: string, allocator := context.allocator) -> string {
|
|||||||
// If there is no slash in path, it returns an empty dir and file set to path
|
// If there is no slash in path, it returns an empty dir and file set to path
|
||||||
// The returned values have the property that path = dir+file
|
// The returned values have the property that path = dir+file
|
||||||
split :: proc(path: string) -> (dir, file: string) {
|
split :: proc(path: string) -> (dir, file: string) {
|
||||||
i := strings.last_index_any(path, OS_SEPARATORS);
|
i := strings.last_index(path, "/");
|
||||||
return path[:i+1], path[i+1:];
|
return path[:i+1], path[i+1:];
|
||||||
}
|
}
|
||||||
|
|
||||||
// split_elements splits the path elements into slices of the original path string
|
// split_elements splits the path elements into slices of the original path string
|
||||||
split_elements :: proc(path: string, allocator := context.allocator) -> []string {
|
split_elements :: proc(path: string, allocator := context.allocator) -> []string {
|
||||||
return strings.split_multi(path, OS_SEPARATORS_ARRAY, true, allocator);
|
return strings.split(path, "/", allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean returns the shortest path name equivalent to path through lexical analysis only
|
// clean returns the shortest path name equivalent to path through lexical analysis only
|
||||||
@@ -206,131 +196,6 @@ name :: proc(path: string, new := false, allocator := context.allocator) -> (nam
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
rel :: proc{rel_between, rel_current};
|
|
||||||
|
|
||||||
// returns the relative path from one path to another
|
|
||||||
rel_between :: proc(from, to: string, allocator := context.allocator) -> string {
|
|
||||||
if from == "" || to == "" {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
from, to := from, to;
|
|
||||||
from = full(from, context.temp_allocator);
|
|
||||||
to = full(to, context.temp_allocator);
|
|
||||||
|
|
||||||
from_is_dir := is_dir(from);
|
|
||||||
to_is_dir := is_dir(to);
|
|
||||||
|
|
||||||
index, slash := 0, 0;
|
|
||||||
|
|
||||||
for {
|
|
||||||
if index >= len(from) {
|
|
||||||
if index >= len(to) || (from_is_dir && index < len(to) && (to[index] == '/' || to[index] == '\\')) {
|
|
||||||
slash = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if index >= len(to) {
|
|
||||||
if index >= len(from) || (to_is_dir && index < len(from) && (from[index] == '/' || from[index] == '\\')) {
|
|
||||||
slash = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lchar, skip := utf8.decode_rune_in_string(from[index:]);
|
|
||||||
rchar, _ := utf8.decode_rune_in_string(to[index:]);
|
|
||||||
|
|
||||||
if (lchar == '/' || lchar == '\\') && (rchar == '/' || lchar == '\\') {
|
|
||||||
slash = index;
|
|
||||||
}
|
|
||||||
else if lchar != rchar {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
index += skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
if slash < 1 {
|
|
||||||
// there is no common path, use the absolute `to` path
|
|
||||||
return strings.clone(to, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
from_slashes, to_slashes := 0, 0;
|
|
||||||
|
|
||||||
if slash < len(from) {
|
|
||||||
from = from[slash+1:];
|
|
||||||
|
|
||||||
if from_is_dir {
|
|
||||||
from_slashes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
from = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if slash < len(to) {
|
|
||||||
to = to[slash+1:];
|
|
||||||
|
|
||||||
if to_is_dir {
|
|
||||||
to_slashes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
to = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
for char in from {
|
|
||||||
if char == '/' || char == '\\' {
|
|
||||||
from_slashes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for char in to {
|
|
||||||
if char == '/' || char == '\\' {
|
|
||||||
to_slashes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if from_slashes == 0 {
|
|
||||||
buffer := make([]byte, 2 + len(to), allocator);
|
|
||||||
|
|
||||||
buffer[0] = '.';
|
|
||||||
buffer[1] = '/';
|
|
||||||
copy(buffer[2:], to);
|
|
||||||
|
|
||||||
return string(buffer);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buffer := make([]byte, from_slashes*3 + len(to), allocator);
|
|
||||||
|
|
||||||
for i in 0..<from_slashes {
|
|
||||||
buffer[i*3+0] = '.';
|
|
||||||
buffer[i*3+1] = '.';
|
|
||||||
buffer[i*3+2] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(buffer[from_slashes*3:], to);
|
|
||||||
|
|
||||||
return string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the relative path from the current directory to another path
|
|
||||||
rel_current :: proc(to: string, allocator := context.allocator) -> string {
|
|
||||||
return rel_between(current(context.allocator), to, allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Lazy_Buffer is a lazily made path buffer
|
Lazy_Buffer is a lazily made path buffer
|
||||||
When it does allocate, it uses the context.allocator
|
When it does allocate, it uses the context.allocator
|
||||||
|
|||||||
+296
-5
@@ -2,6 +2,8 @@ package reflect
|
|||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "intrinsics"
|
||||||
|
_ :: intrinsics;
|
||||||
|
|
||||||
Type_Info :: runtime.Type_Info;
|
Type_Info :: runtime.Type_Info;
|
||||||
|
|
||||||
@@ -551,11 +553,22 @@ union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
|
|||||||
return type_info_of(id);
|
return type_info_of(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
||||||
|
return info.maybe && len(info.variants) == 1 && is_pointer(info.variants[0]);
|
||||||
|
}
|
||||||
|
|
||||||
union_variant_typeid :: proc(a: any) -> typeid {
|
union_variant_typeid :: proc(a: any) -> typeid {
|
||||||
if a == nil { return nil; }
|
if a == nil { return nil; }
|
||||||
|
|
||||||
ti := runtime.type_info_base(type_info_of(a.id));
|
ti := runtime.type_info_base(type_info_of(a.id));
|
||||||
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||||
|
if type_info_union_is_pure_maybe(info) {
|
||||||
|
if a.data != nil {
|
||||||
|
return info.variants[0].id;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
tag_ptr := uintptr(a.data) + info.tag_offset;
|
tag_ptr := uintptr(a.data) + info.tag_offset;
|
||||||
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||||
|
|
||||||
@@ -573,15 +586,159 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if a.data != nil && tag != 0 {
|
if a.data != nil && tag != 0 {
|
||||||
return info.variants[tag-1].id;
|
i := tag if info.no_nil else tag-1;
|
||||||
|
return info.variants[i].id;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic("expected a union to reflect.union_variant_typeid");
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
panic("expected a union to reflect.union_variant_typeid");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||||
|
if a == nil { return -1; }
|
||||||
|
|
||||||
|
ti := runtime.type_info_base(type_info_of(a.id));
|
||||||
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||||
|
if type_info_union_is_pure_maybe(info) {
|
||||||
|
return 1 if a.data != nil else 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_ptr := uintptr(a.data) + info.tag_offset;
|
||||||
|
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||||
|
|
||||||
|
tag: i64 = ---;
|
||||||
|
switch i in tag_any {
|
||||||
|
case u8: tag = i64(i);
|
||||||
|
case i8: tag = i64(i);
|
||||||
|
case u16: tag = i64(i);
|
||||||
|
case i16: tag = i64(i);
|
||||||
|
case u32: tag = i64(i);
|
||||||
|
case i32: tag = i64(i);
|
||||||
|
case u64: tag = i64(i);
|
||||||
|
case i64: tag = i64(i);
|
||||||
|
case: unimplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
panic("expected a union to reflect.get_union_variant_raw_tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
set_union_variant_raw_tag :: proc(a: any, tag: i64) {
|
||||||
|
if a == nil { return; }
|
||||||
|
|
||||||
|
ti := runtime.type_info_base(type_info_of(a.id));
|
||||||
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||||
|
if type_info_union_is_pure_maybe(info) {
|
||||||
|
// Cannot do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_ptr := uintptr(a.data) + info.tag_offset;
|
||||||
|
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
||||||
|
|
||||||
|
switch i in &tag_any {
|
||||||
|
case u8: i = u8(tag);
|
||||||
|
case i8: i = i8(tag);
|
||||||
|
case u16: i = u16(tag);
|
||||||
|
case i16: i = i16(tag);
|
||||||
|
case u32: i = u32(tag);
|
||||||
|
case i32: i = i32(tag);
|
||||||
|
case u64: i = u64(tag);
|
||||||
|
case i64: i = i64(tag);
|
||||||
|
case: unimplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic("expected a union to reflect.set_union_variant_raw_tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_union_variant_typeid :: proc(a: any, id: typeid) {
|
||||||
|
if a == nil { return; }
|
||||||
|
|
||||||
|
ti := runtime.type_info_base(type_info_of(a.id));
|
||||||
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||||
|
if type_info_union_is_pure_maybe(info) {
|
||||||
|
// Cannot do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if id == nil && !info.no_nil {
|
||||||
|
set_union_variant_raw_tag(a, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for variant, i in info.variants {
|
||||||
|
if variant.id == id {
|
||||||
|
tag := i64(i);
|
||||||
|
if !info.no_nil {
|
||||||
|
tag += 1;
|
||||||
|
}
|
||||||
|
set_union_variant_raw_tag(a, tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic("expected a union to reflect.set_union_variant_typeid");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_union_variant_type_info :: proc(a: any, tag_ti: ^Type_Info) {
|
||||||
|
if a == nil { return; }
|
||||||
|
|
||||||
|
ti := runtime.type_info_base(type_info_of(a.id));
|
||||||
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
||||||
|
if type_info_union_is_pure_maybe(info) {
|
||||||
|
// Cannot do anything
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag_ti == nil && !info.no_nil {
|
||||||
|
set_union_variant_raw_tag(a, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for variant, i in info.variants {
|
||||||
|
if variant == tag_ti {
|
||||||
|
tag := i64(i);
|
||||||
|
if !info.no_nil {
|
||||||
|
tag += 1;
|
||||||
|
}
|
||||||
|
set_union_variant_raw_tag(a, tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic("expected a union to reflect.set_union_variant_type_info");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
||||||
|
if a == nil { return; }
|
||||||
|
a := a;
|
||||||
|
ti := runtime.type_info_core(type_info_of(a.id));
|
||||||
|
a.id = ti.id;
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_Boolean:
|
||||||
|
valid = true;
|
||||||
|
switch v in a {
|
||||||
|
case bool: value = bool(v);
|
||||||
|
case b8: value = bool(v);
|
||||||
|
case b16: value = bool(v);
|
||||||
|
case b32: value = bool(v);
|
||||||
|
case b64: value = bool(v);
|
||||||
|
case: valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
||||||
v: i64;
|
v: i64;
|
||||||
@@ -915,3 +1072,137 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||||
|
if a == nil { return; }
|
||||||
|
a := a;
|
||||||
|
ti := runtime.type_info_core(type_info_of(a.id));
|
||||||
|
a.id = ti.id;
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_String:
|
||||||
|
valid = true;
|
||||||
|
switch v in a {
|
||||||
|
case string: value = string(v);
|
||||||
|
case cstring: value = string(v);
|
||||||
|
case: valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||||
|
if a == nil { return nil; }
|
||||||
|
a := a;
|
||||||
|
ti := runtime.type_info_core(type_info_of(a.id));
|
||||||
|
a.id = ti.id;
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_Relative_Pointer:
|
||||||
|
return relative_pointer_to_absolute_raw(a.data, info.base_integer.id);
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||||
|
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
||||||
|
if ptr^ == 0 {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
when intrinsics.type_is_unsigned(T) {
|
||||||
|
return rawptr(uintptr(ptr) + uintptr(ptr^));
|
||||||
|
} else {
|
||||||
|
return rawptr(uintptr(ptr) + uintptr(i64(ptr^)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr_any := any{data, base_integer_id};
|
||||||
|
ptr: rawptr;
|
||||||
|
switch i in &ptr_any {
|
||||||
|
case u8: ptr = _handle(&i);
|
||||||
|
case u16: ptr = _handle(&i);
|
||||||
|
case u32: ptr = _handle(&i);
|
||||||
|
case u64: ptr = _handle(&i);
|
||||||
|
case i8: ptr = _handle(&i);
|
||||||
|
case i16: ptr = _handle(&i);
|
||||||
|
case i32: ptr = _handle(&i);
|
||||||
|
case i64: ptr = _handle(&i);
|
||||||
|
case u16le: ptr = _handle(&i);
|
||||||
|
case u32le: ptr = _handle(&i);
|
||||||
|
case u64le: ptr = _handle(&i);
|
||||||
|
case i16le: ptr = _handle(&i);
|
||||||
|
case i32le: ptr = _handle(&i);
|
||||||
|
case i64le: ptr = _handle(&i);
|
||||||
|
case u16be: ptr = _handle(&i);
|
||||||
|
case u32be: ptr = _handle(&i);
|
||||||
|
case u64be: ptr = _handle(&i);
|
||||||
|
case i16be: ptr = _handle(&i);
|
||||||
|
case i32be: ptr = _handle(&i);
|
||||||
|
case i64be: ptr = _handle(&i);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
|
if a == nil { return; }
|
||||||
|
a := a;
|
||||||
|
ti := runtime.type_info_core(type_info_of(a.id));
|
||||||
|
a.id = ti.id;
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_Pointer:
|
||||||
|
valid = true;
|
||||||
|
value = a.data;
|
||||||
|
|
||||||
|
case Type_Info_String:
|
||||||
|
valid = true;
|
||||||
|
switch v in a {
|
||||||
|
case cstring: value = rawptr(v);
|
||||||
|
case: valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type_Info_Relative_Pointer:
|
||||||
|
valid = true;
|
||||||
|
value = relative_pointer_to_absolute_raw(a.data, info.base_integer.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
|
if a == nil { return; }
|
||||||
|
a := a;
|
||||||
|
ti := runtime.type_info_core(type_info_of(a.id));
|
||||||
|
a.id = ti.id;
|
||||||
|
|
||||||
|
#partial switch info in ti.variant {
|
||||||
|
case Type_Info_String:
|
||||||
|
valid = true;
|
||||||
|
switch v in a {
|
||||||
|
case string: value = raw_data(v);
|
||||||
|
case cstring: value = rawptr(v); // just in case
|
||||||
|
case: valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type_Info_Array:
|
||||||
|
valid = true;
|
||||||
|
value = a.data;
|
||||||
|
|
||||||
|
case Type_Info_Slice:
|
||||||
|
valid = true;
|
||||||
|
value = (^mem.Raw_Slice)(a.data).data;
|
||||||
|
|
||||||
|
case Type_Info_Dynamic_Array:
|
||||||
|
valid = true;
|
||||||
|
value = (^mem.Raw_Dynamic_Array)(a.data).data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: int, index
|
|||||||
handle_error(file, line, column, index, count);
|
handle_error(file, line, column, index, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
slice_handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
|
slice_handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) -> ! {
|
||||||
context = default_context();
|
context = default_context();
|
||||||
fd := os_stderr();
|
fd := os_stderr();
|
||||||
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
|
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
package utf8string
|
||||||
|
|
||||||
|
import "core:unicode/utf8"
|
||||||
|
import "core:runtime"
|
||||||
|
import "builtin"
|
||||||
|
|
||||||
|
String :: struct {
|
||||||
|
contents: string,
|
||||||
|
rune_count: int,
|
||||||
|
|
||||||
|
// cached information
|
||||||
|
non_ascii: int, // index to non-ascii code points
|
||||||
|
width: int, // 0 if ascii
|
||||||
|
byte_pos: int,
|
||||||
|
rune_pos: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_len :: builtin.len; // helper procedure
|
||||||
|
|
||||||
|
init :: proc(s: ^String, contents: string) -> ^String {
|
||||||
|
s.contents = contents;
|
||||||
|
s.byte_pos = 0;
|
||||||
|
s.rune_pos = 0;
|
||||||
|
|
||||||
|
for i in 0..<_len(contents) {
|
||||||
|
if contents[i] >= utf8.RUNE_SELF {
|
||||||
|
s.rune_count = utf8.rune_count_in_string(contents);
|
||||||
|
_, s.width = utf8.decode_rune_in_string(contents);
|
||||||
|
s.non_ascii = i;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.rune_count = _len(contents);
|
||||||
|
s.width = 0;
|
||||||
|
s.non_ascii = _len(contents);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_string :: proc(s: ^String) -> string {
|
||||||
|
return s.contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
len :: proc(s: ^String) -> int {
|
||||||
|
return s.rune_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
is_ascii :: proc(s: ^String) -> bool {
|
||||||
|
return s.width == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
at :: proc(s: ^String, i: int, loc := #caller_location) -> (r: rune) {
|
||||||
|
runtime.bounds_check_error_loc(loc, i, s.rune_count);
|
||||||
|
|
||||||
|
if i < s.non_ascii {
|
||||||
|
return rune(s.contents[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
r, s.width = utf8.decode_rune_in_string(s.contents);
|
||||||
|
s.rune_pos = 0;
|
||||||
|
s.byte_pos = 0;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case s.rune_count-1:
|
||||||
|
r, s.width = utf8.decode_rune_in_string(s.contents);
|
||||||
|
s.rune_pos = i;
|
||||||
|
s.byte_pos = _len(s.contents) - s.width;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case s.rune_pos-1:
|
||||||
|
r, s.width = utf8.decode_rune_in_string(s.contents[0:s.byte_pos]);
|
||||||
|
s.rune_pos = i;
|
||||||
|
s.byte_pos -= s.width;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case s.rune_pos+1:
|
||||||
|
s.rune_pos = i;
|
||||||
|
s.byte_pos += s.width;
|
||||||
|
fallthrough;
|
||||||
|
case s.rune_pos:
|
||||||
|
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linear scan
|
||||||
|
scan_forward := true;
|
||||||
|
if i < s.rune_pos {
|
||||||
|
if i < (s.rune_pos-s.non_ascii)/2 {
|
||||||
|
s.byte_pos, s.rune_pos = s.non_ascii, s.non_ascii;
|
||||||
|
} else {
|
||||||
|
scan_forward = false;
|
||||||
|
}
|
||||||
|
} else if i-s.rune_pos < (s.rune_count-s.rune_pos)/2 {
|
||||||
|
// scan_forward = true;
|
||||||
|
} else {
|
||||||
|
s.byte_pos, s.rune_pos = _len(s.contents), s.rune_count;
|
||||||
|
scan_forward = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if scan_forward {
|
||||||
|
for {
|
||||||
|
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]);
|
||||||
|
if s.rune_pos == i {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.rune_pos += 1;
|
||||||
|
s.byte_pos += s.width;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for {
|
||||||
|
r, s.width = utf8.decode_last_rune_in_string(s.contents[:s.byte_pos]);
|
||||||
|
s.rune_pos -= 1;
|
||||||
|
s.byte_pos -= s.width;
|
||||||
|
if s.rune_pos == i {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice :: proc(s: ^String, i, j: int, loc := #caller_location) -> string {
|
||||||
|
runtime.slice_expr_error_lo_hi_loc(loc, i, j, s.rune_count);
|
||||||
|
|
||||||
|
if j < s.non_ascii {
|
||||||
|
return s.contents[i:j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == j {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
lo, hi: int;
|
||||||
|
if i < s.non_ascii {
|
||||||
|
lo = i;
|
||||||
|
} else if i == s.rune_count {
|
||||||
|
lo = _len(s.contents);
|
||||||
|
} else {
|
||||||
|
at(s, i, loc);
|
||||||
|
lo = s.byte_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if j == s.rune_count {
|
||||||
|
hi = _len(s.contents);
|
||||||
|
} else {
|
||||||
|
at(s, j, loc);
|
||||||
|
hi = s.byte_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.contents[lo:hi];
|
||||||
|
}
|
||||||
@@ -110,6 +110,8 @@ bool does_field_type_allow_using(Type *t) {
|
|||||||
return true;
|
return true;
|
||||||
} else if (is_type_array(t)) {
|
} else if (is_type_array(t)) {
|
||||||
return t->Array.count <= 4;
|
return t->Array.count <= 4;
|
||||||
|
} else if (is_type_typeid(t)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user