Sfoglia il codice sorgente

`split*_iterator` procedures for package bytes and strings

gingerBill 4 anni fa
parent
commit
3337412228
2 ha cambiato i file con 225 aggiunte e 0 eliminazioni
  1. 110 0
      core/bytes/bytes.odin
  2. 115 0
      core/strings/strings.odin

+ 110 - 0
core/bytes/bytes.odin

@@ -203,6 +203,62 @@ split_after_n :: proc(s, sep: []byte, n: int, allocator := context.allocator) ->
 
 
 
+@private
+_split_iterator :: proc(s: ^[]byte, sep: []byte, sep_save, n: int) -> (res: []byte, ok: bool) {
+	s, n := s, n;
+
+	if n == 0 {
+		return;
+	}
+
+	if sep == nil {
+		res = s[:];
+		ok = true;
+		s^ = s[len(s):];
+		return;
+	}
+
+	if n < 0 {
+		n = count(s^, sep) + 1;
+	}
+
+	n -= 1;
+
+	i := 0;
+	for ; i < n; i += 1 {
+		m := index(s^, sep);
+		if m < 0 {
+			break;
+		}
+		res = s[:m+sep_save];
+		ok = true;
+		s^ = s[m+len(sep):];
+		return;
+	}
+	res = s[:];
+	ok = res != nil;
+	s^ = s[len(s):];
+	return;
+}
+
+
+split_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
+	return _split_iterator(s, sep, 0, -1);
+}
+
+split_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
+	return _split_iterator(s, sep, 0, n);
+}
+
+split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
+	return _split_iterator(s, sep, len(sep), -1);
+}
+
+split_after_n_iterator :: proc(s: ^[]byte, sep: []byte, n: int) -> ([]byte, bool) {
+	return _split_iterator(s, sep, len(sep), n);
+}
+
+
 
 index_byte :: proc(s: []byte, c: byte) -> int {
 	for i := 0; i < len(s); i += 1 {
@@ -743,6 +799,60 @@ split_multi :: proc(s: []byte, substrs: [][]byte, skip_empty := false, allocator
 	return buf;
 }
 
+
+
+split_multi_iterator :: proc(s: ^[]byte, substrs: [][]byte, skip_empty := false) -> ([]byte, bool) #no_bounds_check {
+	if s == nil || s^ == nil || len(substrs) <= 0 {
+		return nil, false;
+	}
+
+	sublen := len(substrs[0]);
+
+	for substr in substrs[1:] {
+		sublen = min(sublen, len(substr));
+	}
+
+	shared := len(s) - sublen;
+
+	if shared <= 0 {
+		return nil, false;
+	}
+
+	// index, last
+	i, l := 0, 0;
+
+	loop: for i <= shared {
+		for substr in substrs {
+			if string(s[i:i+sublen]) == string(substr) {
+				if !skip_empty || i - l > 0 {
+					res := s[l:i];
+					s^ = s[i:];
+					return res, true;
+				}
+
+				i += sublen;
+				l  = i;
+
+				continue loop;
+			}
+		}
+
+		_, skip := utf8.decode_rune(s[i:]);
+		i += skip;
+	}
+
+	if !skip_empty || len(s) - l > 0 {
+		res := s[l:];
+		s^ = s[len(s):];
+		return res, true;
+	}
+
+	return nil, false;
+}
+
+
+
+
 // scrub scruvs invalid utf-8 characters and replaces them with the replacement string
 // Adjacent invalid bytes are only replaced once
 scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> []byte {

+ 115 - 0
core/strings/strings.odin

@@ -215,6 +215,64 @@ split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) ->
 }
 
 
+@private
+_split_iterator :: proc(s: ^string, sep: string, sep_save, n: int) -> (res: string, ok: bool) {
+	s, n := s, n;
+
+	if n == 0 {
+		return;
+	}
+
+	if sep == "" {
+		res = s[:];
+		ok = true;
+		s^ = s[len(s):];
+		return;
+	}
+
+	if n < 0 {
+		n = count(s^, sep) + 1;
+	}
+
+	n -= 1;
+
+	i := 0;
+	for ; i < n; i += 1 {
+		m := index(s^, sep);
+		if m < 0 {
+			break;
+		}
+		res = s[:m+sep_save];
+		ok = true;
+		s^ = s[m+len(sep):];
+		return;
+	}
+	res = s[:];
+	ok = res != "";
+	s^ = s[len(s):];
+	return;
+}
+
+
+split_iterator :: proc(s: ^string, sep: string) -> (string, bool) {
+	return _split_iterator(s, sep, 0, -1);
+}
+
+split_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) {
+	return _split_iterator(s, sep, 0, n);
+}
+
+split_after_iterator :: proc(s: ^string, sep: string) -> (string, bool) {
+	return _split_iterator(s, sep, len(sep), -1);
+}
+
+split_after_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool) {
+	return _split_iterator(s, sep, len(sep), n);
+}
+
+
+
+
 
 
 index_byte :: proc(s: string, c: byte) -> int {
@@ -756,6 +814,63 @@ split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator
 	return buf;
 }
 
+
+
+
+split_multi_iterator :: proc(s: ^string, substrs: []string, skip_empty := false) -> (string, bool) #no_bounds_check {
+	if s == nil || s^ == "" || len(substrs) <= 0 {
+		return "", false;
+	}
+
+	sublen := len(substrs[0]);
+
+	for substr in substrs[1:] {
+		sublen = min(sublen, len(substr));
+	}
+
+	shared := len(s) - sublen;
+
+	if shared <= 0 {
+		return "", false;
+	}
+
+	// index, last
+	i, l := 0, 0;
+
+	loop: for i <= shared {
+		for substr in substrs {
+			if s[i:i+sublen] == substr {
+				if !skip_empty || i - l > 0 {
+					res := s[l:i];
+					s^ = s[i:];
+					return res, true;
+				}
+
+				i += sublen;
+				l  = i;
+
+				continue loop;
+			}
+		}
+
+		_, skip := utf8.decode_rune_in_string(s[i:]);
+		i += skip;
+	}
+
+	if !skip_empty || len(s) - l > 0 {
+		res := s[l:];
+		s^ = s[len(s):];
+		return res, true;
+	}
+
+	return "", false;
+}
+
+
+
+
+
+
 // scrub scruvs invalid utf-8 characters and replaces them with the replacement string
 // Adjacent invalid bytes are only replaced once
 scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {