aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Viney <richard.viney@gmail.com>2024-10-07 10:57:50 +1300
committerLouis Pilfold <louis@lpil.uk>2024-10-09 17:43:58 +0100
commit4c3ea2086cf7662f79628f26abff15307ff5bce9 (patch)
tree43d91c59faa8ab4d97e416eff374a25dc26b9603
parent0a087d5d80b803e70909848f5b7b28ce2b5df4fc (diff)
downloadgleam_stdlib-4c3ea2086cf7662f79628f26abff15307ff5bce9.tar.gz
gleam_stdlib-4c3ea2086cf7662f79628f26abff15307ff5bce9.zip
Optimise string.pad_left, string.pad_right. Optimise string.slice on JS.
-rw-r--r--src/gleam/string.gleam50
-rw-r--r--src/gleam_stdlib.mjs28
2 files changed, 53 insertions, 25 deletions
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index 0906481..1b2e3a0 100644
--- a/src/gleam/string.gleam
+++ b/src/gleam/string.gleam
@@ -1,7 +1,7 @@
//// Strings in Gleam are UTF-8 binaries. They can be written in your code as
//// text surrounded by `"double quotes"`.
-import gleam/iterator.{type Iterator}
+import gleam/iterator
import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/order
@@ -222,13 +222,8 @@ pub fn slice(from string: String, at_index idx: Int, length len: Int) -> String
}
@external(erlang, "gleam_stdlib", "slice")
-fn do_slice(string: String, idx: Int, len: Int) -> String {
- string
- |> to_graphemes
- |> list.drop(idx)
- |> list.take(len)
- |> concat
-}
+@external(javascript, "../gleam_stdlib.mjs", "string_slice")
+fn do_slice(string: String, idx: Int, len: Int) -> String
/// Drops contents of the first `String` that occur before the second `String`.
/// If the `from` string does not contain the `before` string, `from` is returned unchanged.
@@ -489,13 +484,18 @@ fn do_join(strings: List(String), separator: String) -> String {
/// // -> "121"
/// ```
///
-pub fn pad_left(string: String, to desired_length: Int, with pad_string: String) {
+pub fn pad_left(
+ string: String,
+ to desired_length: Int,
+ with pad_string: String,
+) -> String {
let current_length = length(string)
let to_pad_length = desired_length - current_length
- padding(to_pad_length, pad_string)
- |> iterator.append(iterator.single(string))
- |> iterator.to_list
- |> concat
+
+ case to_pad_length <= 0 {
+ True -> string
+ False -> padding(to_pad_length, pad_string) <> string
+ }
}
/// Pads a `String` on the right until it has a given length.
@@ -521,22 +521,22 @@ pub fn pad_right(
string: String,
to desired_length: Int,
with pad_string: String,
-) {
+) -> String {
let current_length = length(string)
let to_pad_length = desired_length - current_length
- iterator.single(string)
- |> iterator.append(padding(to_pad_length, pad_string))
- |> iterator.to_list
- |> concat
+
+ case to_pad_length <= 0 {
+ True -> string
+ False -> string <> padding(to_pad_length, pad_string)
+ }
}
-fn padding(size: Int, pad_string: String) -> Iterator(String) {
- let pad_length = length(pad_string)
- let num_pads = size / pad_length
- let extra = size % pad_length
- iterator.repeat(pad_string)
- |> iterator.take(num_pads)
- |> iterator.append(iterator.single(slice(pad_string, 0, extra)))
+fn padding(size: Int, pad_string: String) -> String {
+ let pad_string_length = length(pad_string)
+ let num_pads = size / pad_string_length
+ let extra = size % pad_string_length
+
+ repeat(pad_string, num_pads) <> slice(pad_string, 0, extra)
}
/// Removes whitespace on both sides of a `String`.
diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs
index 1aa4753..58a032e 100644
--- a/src/gleam_stdlib.mjs
+++ b/src/gleam_stdlib.mjs
@@ -223,6 +223,34 @@ export function length(data) {
return data.length;
}
+export function string_slice(string, idx, len) {
+ if (len <= 0 || idx >= string.length) {
+ return "";
+ }
+
+ const iterator = graphemes_iterator(string);
+ if (iterator) {
+ while (idx-- > 0) {
+ iterator.next();
+ }
+
+ let result = "";
+
+ while (len-- > 0) {
+ const v = iterator.next().value;
+ if (v === undefined) {
+ break;
+ }
+
+ result += v.segment;
+ }
+
+ return result;
+ } else {
+ return string.match(/./gsu).slice(idx, idx + len).join("");
+ }
+}
+
export function crop_string(string, substring) {
return string.substring(string.indexOf(substring));
}