mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-16 08:04:07 +00:00
Reorganize package strings
This commit is contained in:
@@ -93,18 +93,18 @@ mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
when ODIN_USE_LLVM_API {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
}
|
||||
} else {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
llvm_memmove :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,18 +121,18 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r
|
||||
when ODIN_USE_LLVM_API {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, is_volatile: bool = false) ---;
|
||||
}
|
||||
} else {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
llvm_memcpy :: proc "none" (dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,45 +389,45 @@ string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4;
|
||||
}
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
@(default_calling_convention = "none")
|
||||
foreign {
|
||||
@(link_name="llvm.sqrt.f32") _sqrt_f32 :: proc(x: f32) -> f32 ---
|
||||
@(link_name="llvm.sqrt.f64") _sqrt_f64 :: proc(x: f64) -> f64 ---
|
||||
}
|
||||
abs_f32 :: inline proc "contextless" (x: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.fabs.f32") _abs :: proc "c" (x: f32) -> f32 ---
|
||||
@(link_name="llvm.fabs.f32") _abs :: proc "none" (x: f32) -> f32 ---
|
||||
}
|
||||
return _abs(x);
|
||||
}
|
||||
abs_f64 :: inline proc "contextless" (x: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.fabs.f64") _abs :: proc "c" (x: f64) -> f64 ---
|
||||
@(link_name="llvm.fabs.f64") _abs :: proc "none" (x: f64) -> f64 ---
|
||||
}
|
||||
return _abs(x);
|
||||
}
|
||||
|
||||
min_f32 :: proc(a, b: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.minnum.f32") _min :: proc "c" (a, b: f32) -> f32 ---
|
||||
@(link_name="llvm.minnum.f32") _min :: proc "none" (a, b: f32) -> f32 ---
|
||||
}
|
||||
return _min(a, b);
|
||||
}
|
||||
min_f64 :: proc(a, b: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.minnum.f64") _min :: proc "c" (a, b: f64) -> f64 ---
|
||||
@(link_name="llvm.minnum.f64") _min :: proc "none" (a, b: f64) -> f64 ---
|
||||
}
|
||||
return _min(a, b);
|
||||
}
|
||||
max_f32 :: proc(a, b: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.maxnum.f32") _max :: proc "c" (a, b: f32) -> f32 ---
|
||||
@(link_name="llvm.maxnum.f32") _max :: proc "none" (a, b: f32) -> f32 ---
|
||||
}
|
||||
return _max(a, b);
|
||||
}
|
||||
max_f64 :: proc(a, b: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.maxnum.f64") _max :: proc "c" (a, b: f64) -> f64 ---
|
||||
@(link_name="llvm.maxnum.f64") _max :: proc "none" (a, b: f64) -> f64 ---
|
||||
}
|
||||
return _max(a, b);
|
||||
}
|
||||
|
||||
254
core/strings/conversion.odin
Normal file
254
core/strings/conversion.odin
Normal file
@@ -0,0 +1,254 @@
|
||||
package strings
|
||||
|
||||
to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string {
|
||||
if len(s) == 0 {
|
||||
return "";
|
||||
}
|
||||
|
||||
b := make_builder_len_cap(0, 0, allocator);
|
||||
|
||||
s := s;
|
||||
for c, i in s {
|
||||
if c != utf8.RUNE_ERROR {
|
||||
continue;
|
||||
}
|
||||
|
||||
_, w := utf8.decode_rune_in_string(s[i:]);
|
||||
if w == 1 {
|
||||
grow_builder(&b, len(s) + len(replacement));
|
||||
write_string(&b, s[:i]);
|
||||
s = s[i:];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if builder_cap(b) == 0 {
|
||||
return clone(s, allocator);
|
||||
}
|
||||
|
||||
invalid := false;
|
||||
|
||||
for i := 0; i < len(s); /**/ {
|
||||
c := s[i];
|
||||
if c < utf8.RUNE_SELF {
|
||||
i += 1;
|
||||
invalid = false;
|
||||
write_byte(&b, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
_, w := utf8.decode_rune_in_string(s[i:]);
|
||||
if w == 1 {
|
||||
i += 1;
|
||||
if !invalid {
|
||||
invalid = true;
|
||||
write_string(&b, replacement);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
invalid = false;
|
||||
write_string(&b, s[i:][:w]);
|
||||
i += w;
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
to_lower :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b := make_builder(0, len(s), allocator);
|
||||
for r in s {
|
||||
write_rune(&b, unicode.to_lower(r));
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
to_upper :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b := make_builder(0, len(s), allocator);
|
||||
for r in s {
|
||||
write_rune(&b, unicode.to_upper(r));
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
is_delimiter :: proc(c: rune) -> bool {
|
||||
return c == '-' || c == '_' || is_space(c);
|
||||
}
|
||||
|
||||
is_separator :: proc(r: rune) -> bool {
|
||||
if r <= 0x7f {
|
||||
switch r {
|
||||
case '0'..'9': return false;
|
||||
case 'a'..'z': return false;
|
||||
case 'A'..'Z': return false;
|
||||
case '_': return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(bill): unicode categories
|
||||
// if unicode.is_letter(r) || unicode.is_digit(r) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return unicode.is_space(r);
|
||||
}
|
||||
|
||||
|
||||
string_case_iterator :: proc(b: ^Builder, s: string, callback: proc(b: ^Builder, prev, curr, next: rune)) {
|
||||
prev, curr: rune;
|
||||
for next in s {
|
||||
if curr == 0 {
|
||||
prev = curr;
|
||||
curr = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(b, prev, curr, next);
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
callback(b, prev, curr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
to_lower_camel_case :: to_camel_case;
|
||||
to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
string_case_iterator(&b, s, proc(b: ^Builder, prev, curr, next: rune) {
|
||||
if !is_delimiter(curr) {
|
||||
if is_delimiter(prev) {
|
||||
write_rune(b, unicode.to_upper(curr));
|
||||
} else if unicode.is_lower(prev) {
|
||||
write_rune(b, curr);
|
||||
} else {
|
||||
write_rune(b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
to_upper_camel_case :: to_pascal_case;
|
||||
to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
string_case_iterator(&b, s, proc(b: ^Builder, prev, curr, next: rune) {
|
||||
if !is_delimiter(curr) {
|
||||
if is_delimiter(prev) || prev == 0 {
|
||||
write_rune(b, unicode.to_upper(curr));
|
||||
} else if unicode.is_lower(prev) {
|
||||
write_rune(b, curr);
|
||||
} else {
|
||||
write_rune(b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower;
|
||||
|
||||
prev, curr: rune;
|
||||
|
||||
for next in s {
|
||||
if is_delimiter(curr) {
|
||||
if !is_delimiter(prev) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
} else if unicode.is_upper(curr) {
|
||||
if unicode.is_lower(prev) || (unicode.is_upper(prev) && unicode.is_lower(next)) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, adjust_case(curr));
|
||||
} else if curr != 0 {
|
||||
write_rune(&b, adjust_case(curr));
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
if unicode.is_upper(curr) && unicode.is_lower(prev) && prev != 0 {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, adjust_case(curr));
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
to_snake_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '_', false, allocator);
|
||||
}
|
||||
|
||||
to_screaming_snake_case :: to_upper_snake_case;
|
||||
to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '_', true, allocator);
|
||||
}
|
||||
|
||||
to_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '-', false, allocator);
|
||||
}
|
||||
|
||||
to_upper_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '-', true, allocator);
|
||||
}
|
||||
|
||||
to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
delimiter :: '_';
|
||||
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
prev, curr: rune;
|
||||
|
||||
for next in s {
|
||||
if is_delimiter(curr) {
|
||||
if !is_delimiter(prev) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
} else if unicode.is_upper(curr) {
|
||||
if unicode.is_lower(prev) || (unicode.is_upper(prev) && unicode.is_lower(next)) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, unicode.to_upper(curr));
|
||||
} else if curr != 0 {
|
||||
write_rune(&b, unicode.to_lower(curr));
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
if unicode.is_upper(curr) && unicode.is_lower(prev) && prev != 0 {
|
||||
write_rune(&b, delimiter);
|
||||
write_rune(&b, unicode.to_upper(curr));
|
||||
} else {
|
||||
write_rune(&b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
@@ -787,207 +787,6 @@ scrub :: proc(s: string, replacement: string, allocator := context.allocator) ->
|
||||
}
|
||||
|
||||
|
||||
to_lower :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b := make_builder(0, len(s), allocator);
|
||||
for r in s {
|
||||
write_rune(&b, unicode.to_lower(r));
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
to_upper :: proc(s: string, allocator := context.allocator) -> string {
|
||||
b := make_builder(0, len(s), allocator);
|
||||
for r in s {
|
||||
write_rune(&b, unicode.to_upper(r));
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
is_delimiter :: proc(c: rune) -> bool {
|
||||
return c == '-' || c == '_' || is_space(c);
|
||||
}
|
||||
|
||||
is_separator :: proc(r: rune) -> bool {
|
||||
if r <= 0x7f {
|
||||
switch r {
|
||||
case '0'..'9': return false;
|
||||
case 'a'..'z': return false;
|
||||
case 'A'..'Z': return false;
|
||||
case '_': return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(bill): unicode categories
|
||||
// if unicode.is_letter(r) || unicode.is_digit(r) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return unicode.is_space(r);
|
||||
}
|
||||
|
||||
|
||||
string_case_iterator :: proc(b: ^Builder, s: string, callback: proc(b: ^Builder, prev, curr, next: rune)) {
|
||||
prev, curr: rune;
|
||||
for next in s {
|
||||
if curr == 0 {
|
||||
prev = curr;
|
||||
curr = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
callback(b, prev, curr, next);
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
callback(b, prev, curr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
to_lower_camel_case :: to_camel_case;
|
||||
to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
string_case_iterator(&b, s, proc(b: ^Builder, prev, curr, next: rune) {
|
||||
if !is_delimiter(curr) {
|
||||
if is_delimiter(prev) {
|
||||
write_rune(b, unicode.to_upper(curr));
|
||||
} else if unicode.is_lower(prev) {
|
||||
write_rune(b, curr);
|
||||
} else {
|
||||
write_rune(b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
to_upper_camel_case :: to_pascal_case;
|
||||
to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
string_case_iterator(&b, s, proc(b: ^Builder, prev, curr, next: rune) {
|
||||
if !is_delimiter(curr) {
|
||||
if is_delimiter(prev) || prev == 0 {
|
||||
write_rune(b, unicode.to_upper(curr));
|
||||
} else if unicode.is_lower(prev) {
|
||||
write_rune(b, curr);
|
||||
} else {
|
||||
write_rune(b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allocator := context.allocator) -> string {
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower;
|
||||
|
||||
prev, curr: rune;
|
||||
|
||||
for next in s {
|
||||
if is_delimiter(curr) {
|
||||
if !is_delimiter(prev) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
} else if unicode.is_upper(curr) {
|
||||
if unicode.is_lower(prev) || (unicode.is_upper(prev) && unicode.is_lower(next)) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, adjust_case(curr));
|
||||
} else if curr != 0 {
|
||||
write_rune(&b, adjust_case(curr));
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
if unicode.is_upper(curr) && unicode.is_lower(prev) && prev != 0 {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, adjust_case(curr));
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
to_snake_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '_', false, allocator);
|
||||
}
|
||||
|
||||
to_screaming_snake_case :: to_upper_snake_case;
|
||||
to_upper_snake_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '_', true, allocator);
|
||||
}
|
||||
|
||||
to_kebab_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '-', false, allocator);
|
||||
}
|
||||
|
||||
to_upper_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
return to_delimiter_case(s, '-', true, allocator);
|
||||
}
|
||||
|
||||
to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
|
||||
delimiter :: '_';
|
||||
|
||||
s := s;
|
||||
s = trim_space(s);
|
||||
b := make_builder(0, len(s), allocator);
|
||||
|
||||
prev, curr: rune;
|
||||
|
||||
for next in s {
|
||||
if is_delimiter(curr) {
|
||||
if !is_delimiter(prev) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
} else if unicode.is_upper(curr) {
|
||||
if unicode.is_lower(prev) || (unicode.is_upper(prev) && unicode.is_lower(next)) {
|
||||
write_rune(&b, delimiter);
|
||||
}
|
||||
write_rune(&b, unicode.to_upper(curr));
|
||||
} else if curr != 0 {
|
||||
write_rune(&b, unicode.to_lower(curr));
|
||||
}
|
||||
|
||||
prev = curr;
|
||||
curr = next;
|
||||
}
|
||||
|
||||
if len(s) > 0 {
|
||||
if unicode.is_upper(curr) && unicode.is_lower(prev) && prev != 0 {
|
||||
write_rune(&b, delimiter);
|
||||
write_rune(&b, unicode.to_upper(curr));
|
||||
} else {
|
||||
write_rune(&b, unicode.to_lower(curr));
|
||||
}
|
||||
}
|
||||
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
reverse :: proc(s: string, allocator := context.allocator) -> string {
|
||||
str := s;
|
||||
n := len(str);
|
||||
@@ -1120,60 +919,6 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
|
||||
|
||||
|
||||
|
||||
to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string {
|
||||
if len(s) == 0 {
|
||||
return "";
|
||||
}
|
||||
|
||||
b := make_builder_len_cap(0, 0, allocator);
|
||||
|
||||
s := s;
|
||||
for c, i in s {
|
||||
if c != utf8.RUNE_ERROR {
|
||||
continue;
|
||||
}
|
||||
|
||||
_, w := utf8.decode_rune_in_string(s[i:]);
|
||||
if w == 1 {
|
||||
grow_builder(&b, len(s) + len(replacement));
|
||||
write_string(&b, s[:i]);
|
||||
s = s[i:];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if builder_cap(b) == 0 {
|
||||
return clone(s, allocator);
|
||||
}
|
||||
|
||||
invalid := false;
|
||||
|
||||
for i := 0; i < len(s); /**/ {
|
||||
c := s[i];
|
||||
if c < utf8.RUNE_SELF {
|
||||
i += 1;
|
||||
invalid = false;
|
||||
write_byte(&b, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
_, w := utf8.decode_rune_in_string(s[i:]);
|
||||
if w == 1 {
|
||||
i += 1;
|
||||
if !invalid {
|
||||
invalid = true;
|
||||
write_string(&b, replacement);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
invalid = false;
|
||||
write_string(&b, s[i:][:w]);
|
||||
i += w;
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@private
|
||||
write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) {
|
||||
|
||||
Reference in New Issue
Block a user