mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-19 01:18:22 +00:00
Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
|
||||
155
core/unicode/utf8/utf8string/string.odin
Normal file
155
core/unicode/utf8/utf8string/string.odin
Normal 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];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user