This commit is contained in:
Platin21
2020-09-27 22:13:12 +03:00
8 changed files with 474 additions and 203 deletions

View File

@@ -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 {
strings.write_string(fi.buf, "nil");
} else {
@@ -1877,59 +1877,13 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_opaque(fi, v);
case runtime.Type_Info_Relative_Pointer:
ptr_any := any{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);
}
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id);
absolute_ptr := any{ptr, info.pointer.id};
fmt_value(fi, absolute_ptr, verb);
case runtime.Type_Info_Relative_Slice:
ptr_any := any{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);
}
ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id);
if verb == 'p' {
fmt_pointer(fi, ptr, 'p');

View File

@@ -4,7 +4,7 @@ import win32 "core:sys/windows"
import "core:strings"
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) {
// Ignore "." and ".."
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;
}
context.allocator = allocator;
h := win32.HANDLE(fd);
dir_fi, _ := stat_from_file_information("", h);

View File

@@ -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
import "core:os"

View File

@@ -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
import "core:strings"
@@ -5,29 +10,14 @@ import "core:runtime"
import "core:unicode/utf8"
// is_separator checks whether the byte is a valid separator character
is_separator :: proc(c: byte) -> bool {
switch c {
case '/': return true;
case '\\': return ODIN_OS == "windows";
}
return false;
is_separator :: inline proc(c: byte) -> bool {
return c == '/';
}
// is_abs checks whether the path is absolute
is_abs :: proc(path: string) -> bool {
if 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;
is_abs :: inline proc(path: string) -> bool {
return len(path) > 0 && path[0] == '/';
}
@@ -51,7 +41,7 @@ base :: proc(path: string, new := false, allocator := context.allocator) -> (las
for len(path) > 0 && is_separator(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:];
}
@@ -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
// The returned values have the property that path = dir+file
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:];
}
// split_elements splits the path elements into slices of the original path 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
@@ -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
When it does allocate, it uses the context.allocator

View File

@@ -2,6 +2,8 @@ package reflect
import "core:runtime"
import "core:mem"
import "intrinsics"
_ :: intrinsics;
Type_Info :: runtime.Type_Info;
@@ -551,11 +553,22 @@ union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
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 {
if a == nil { return nil; }
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) {
if a.data != nil {
return info.variants[0].id;
}
return nil;
}
tag_ptr := uintptr(a.data) + info.tag_offset;
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 {
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) {
v: i64;
@@ -915,3 +1072,137 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
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;
}

View File

@@ -35,7 +35,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: int, index
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();
fd := os_stderr();
print_caller_location(fd, Source_Code_Location{file, line, column, "", 0});

View File

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

View File

@@ -110,6 +110,8 @@ bool does_field_type_allow_using(Type *t) {
return true;
} else if (is_type_array(t)) {
return t->Array.count <= 4;
} else if (is_type_typeid(t)) {
return true;
}
return false;
}