aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2020-06-26 17:47:09 +0100
committerLouis Pilfold <louis@lpil.uk>2020-06-30 12:14:27 +0100
commitc5f596770a20ac4afdd3c7fd37bfb8550605cbe9 (patch)
treead1897084ba811e8970d2a3a33d7d59082a9897d
parentd90199e49c75d051853af52156ee8adaddc58564 (diff)
downloadgleam_stdlib-c5f596770a20ac4afdd3c7fd37bfb8550605cbe9.tar.gz
gleam_stdlib-c5f596770a20ac4afdd3c7fd37bfb8550605cbe9.zip
iodata -> string_builder
-rw-r--r--src/gleam/float.gleam6
-rw-r--r--src/gleam/iodata.gleam159
-rw-r--r--src/gleam/string.gleam38
-rw-r--r--src/gleam/string_builder.gleam168
-rw-r--r--test/gleam/iodata_test.gleam96
-rw-r--r--test/gleam/string_builder_test.gleam105
6 files changed, 295 insertions, 277 deletions
diff --git a/src/gleam/float.gleam b/src/gleam/float.gleam
index 953a267..f810161 100644
--- a/src/gleam/float.gleam
+++ b/src/gleam/float.gleam
@@ -1,4 +1,4 @@
-import gleam/iodata
+import gleam/string_builder
import gleam/order.{Order}
pub type Float =
@@ -25,8 +25,8 @@ pub external fn parse(String) -> Result(Float, Nil) =
///
pub fn to_string(f: Float) -> String {
f
- |> iodata.from_float
- |> iodata.to_string
+ |> string_builder.from_float
+ |> string_builder.to_string
}
/// Compares two floats, returning an order.
diff --git a/src/gleam/iodata.gleam b/src/gleam/iodata.gleam
deleted file mode 100644
index fe24974..0000000
--- a/src/gleam/iodata.gleam
+++ /dev/null
@@ -1,159 +0,0 @@
-/// Iodata is a type used for efficiently building strings.
-///
-/// When we append one string to another the strings must be copied to a
-/// new location in memory so that they can sit together. This behaviour
-/// enables efficient reading of the string but copying can be expensive,
-/// especially if we want to join many strings together.
-///
-/// Iodata is different in that it can be joined together in constant time
-/// using minimal memory, and then can be efficiently converted to a string
-/// using the `to_string` function.
-///
-pub external type Iodata
-
-/// Prepend a String onto the start of some Iodata.
-///
-/// Runs in constant time.
-///
-pub external fn prepend(to: Iodata, prefix: String) -> Iodata =
- "gleam_stdlib" "iodata_prepend"
-
-/// Append a String onto the end of some Iodata.
-///
-/// Runs in constant time.
-///
-pub external fn append(to: Iodata, suffix: String) -> Iodata =
- "gleam_stdlib" "iodata_append"
-
-/// Prepend some Iodata onto the start of another.
-///
-/// Runs in constant time.
-///
-pub external fn prepend_iodata(to: Iodata, prefix: Iodata) -> Iodata =
- "gleam_stdlib" "iodata_prepend"
-
-/// Append some Iodata onto the end of another.
-///
-/// Runs in constant time.
-///
-pub external fn append_iodata(to: Iodata, suffix: Iodata) -> Iodata =
- "gleam_stdlib" "iodata_append"
-
-/// Convert a list of strings into iodata.
-///
-/// Runs in constant time.
-///
-pub external fn from_strings(List(String)) -> Iodata =
- "gleam_stdlib" "identity"
-
-/// Joins a list of iodata into a single iodata.
-///
-/// Runs in constant time.
-///
-pub external fn concat(List(Iodata)) -> Iodata =
- "gleam_stdlib" "identity"
-
-/// Convert a string into iodata.
-///
-/// Runs in constant time.
-///
-pub external fn new(String) -> Iodata =
- "gleam_stdlib" "identity"
-
-/// Turns an `Iodata` into a `String`
-///
-/// This function is implemented natively by the virtual machine and is highly
-/// optimised.
-///
-pub external fn to_string(Iodata) -> String =
- "erlang" "iolist_to_binary"
-
-/// Returns the size of the Iodata in bytes.
-///
-pub external fn byte_size(Iodata) -> Int =
- "erlang" "iolist_size"
-
-/// Creates textual representation of the given float as iodata.
-///
-pub external fn from_float(Float) -> Iodata =
- "io_lib_format" "fwrite_g"
-
-/// Converts Iodata to a new Iodata where valid UTF-8 string data is
-/// lowercased.
-///
-pub external fn lowercase(Iodata) -> Iodata =
- "string" "lowercase"
-
-/// Converts Iodata to a new Iodata where valid UTF-8 string data is
-/// uppercased.
-///
-pub external fn uppercase(Iodata) -> Iodata =
- "string" "uppercase"
-
-/// Converts Iodata to a new Iodata where valid UTF-8 string data is
-/// reversed.
-///
-pub external fn reverse(Iodata) -> Iodata =
- "string" "reverse"
-
-type Direction {
- All
-}
-
-external fn erl_split(Iodata, String, Direction) -> List(Iodata) =
- "string" "split"
-
-/// Splits iodata on a given pattern into a list of iodata.
-///
-pub fn split(iodata: Iodata, on pattern: String) -> List(Iodata) {
- erl_split(iodata, pattern, All)
-}
-
-external fn erl_replace(Iodata, String, String, Direction) -> Iodata =
- "string" "replace"
-
-/// Replaces all instances of a pattern with a given string substitute.
-///
-pub fn replace(
- in iodata: Iodata,
- each pattern: String,
- with substitute: String,
-) -> Iodata {
- erl_replace(iodata, pattern, substitute, All)
-}
-
-/// Compare two pieces of iodata to determine if they have the same textual
-/// content.
-///
-/// Comparing two iodata using the `==` operator may return False even if they
-/// have the same content as they may have been build in different ways, so
-/// using this function is often preferred.
-///
-/// ## Examples
-///
-/// > from_strings(["a", "b"]) == new("ab")
-/// False
-///
-/// > is_equal(from_strings(["a", "b"]), new("ab"))
-/// True
-///
-///
-pub external fn is_equal(Iodata, Iodata) -> Bool =
- "string" "equal"
-
-/// Inspect some iodata to determine if it is equivalent to an empty string.
-///
-/// ## Examples
-///
-/// > new("ok") |> is_empty
-/// False
-///
-/// > new("") |> is_empty
-/// True
-///
-/// > from_strings([]) |> is_empty
-/// True
-///
-///
-pub external fn is_empty(Iodata) -> Bool =
- "string" "is_empty"
diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam
index 740f90b..1714dad 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 a
//// text surrounded by `"double quotes"`.
-import gleam/iodata
+import gleam/string_builder
import gleam/dynamic.{Dynamic}
import gleam/list
import gleam/order
@@ -56,9 +56,9 @@ pub external fn length(String) -> Int =
///
pub fn reverse(string: String) -> String {
string
- |> iodata.new
- |> iodata.reverse
- |> iodata.to_string
+ |> string_builder.from_string
+ |> string_builder.reverse
+ |> string_builder.to_string
}
/// Create a new string by replacing all occurrences of a given substring.
@@ -77,9 +77,9 @@ pub fn replace(
with substitute: String,
) -> String {
string
- |> iodata.new
- |> iodata.replace(each: pattern, with: substitute)
- |> iodata.to_string
+ |> string_builder.from_string
+ |> string_builder.replace(each: pattern, with: substitute)
+ |> string_builder.to_string
}
/// Create a new string with all the graphemes in the input string converted to
@@ -243,9 +243,9 @@ pub external fn ends_with(String, String) -> Bool =
///
pub fn split(x: String, on substring: String) -> List(String) {
x
- |> iodata.new
- |> iodata.split(on: substring)
- |> list.map(with: iodata.to_string)
+ |> string_builder.from_string
+ |> string_builder.split(on: substring)
+ |> list.map(with: string_builder.to_string)
}
external fn erl_split(String, String) -> List(String) =
@@ -276,7 +276,7 @@ pub fn split_once(
/// Create a new string by joining two strings together.
///
/// This function copies both strings and runs in linear time. If you find
-/// yourself joining strings frequently consider using the [iodata](../iodata)
+/// yourself joining strings frequently consider using the [string_builder](../iodata)
/// module as it can append strings much faster!
///
/// ## Examples
@@ -286,15 +286,15 @@ pub fn split_once(
///
pub fn append(to first: String, suffix second: String) -> String {
first
- |> iodata.new
- |> iodata.append(second)
- |> iodata.to_string
+ |> string_builder.from_string
+ |> string_builder.append(second)
+ |> string_builder.to_string
}
/// Create a new string by joining many strings together.
///
/// This function copies both strings and runs in linear time. If you find
-/// yourself joining strings frequently consider using the [iodata](../iodata)
+/// yourself joining strings frequently consider using the [string_builder](../iodata)
/// module as it can append strings much faster!
///
/// ## Examples
@@ -304,8 +304,8 @@ pub fn append(to first: String, suffix second: String) -> String {
///
pub fn concat(strings: List(String)) -> String {
strings
- |> iodata.from_strings
- |> iodata.to_string
+ |> string_builder.from_strings
+ |> string_builder.to_string
}
fn repeat_help(chunk: String, result: List(String), repeats: Int) -> String {
@@ -340,8 +340,8 @@ pub fn repeat(string: String, times times: Int) -> String {
pub fn join(strings: List(String), with separator: String) -> String {
strings
|> list.intersperse(with: separator)
- |> iodata.from_strings
- |> iodata.to_string
+ |> string_builder.from_strings
+ |> string_builder.to_string
}
type Direction {
diff --git a/src/gleam/string_builder.gleam b/src/gleam/string_builder.gleam
new file mode 100644
index 0000000..5acf8e1
--- /dev/null
+++ b/src/gleam/string_builder.gleam
@@ -0,0 +1,168 @@
+/// StringBuilder is a type used for efficiently building strings.
+///
+/// When we append one string to another the strings must be copied to a
+/// new location in memory so that they can sit together. This behaviour
+/// enables efficient reading of the string but copying can be expensive,
+/// especially if we want to join many strings together.
+///
+/// StringBuilder is different in that it can be joined together in constant time
+/// using minimal memory, and then can be efficiently converted to a string
+/// using the `to_string` function.
+///
+pub external type StringBuilder
+
+/// Prepend a String onto the start of some StringBuilder.
+///
+/// Runs in constant time.
+///
+pub external fn prepend(to: StringBuilder, prefix: String) -> StringBuilder =
+ "gleam_stdlib" "iodata_prepend"
+
+/// Append a String onto the end of some StringBuilder.
+///
+/// Runs in constant time.
+///
+pub external fn append(to: StringBuilder, suffix: String) -> StringBuilder =
+ "gleam_stdlib" "iodata_append"
+
+/// Prepend some StringBuilder onto the start of another.
+///
+/// Runs in constant time.
+///
+pub external fn prepend_builder(
+ to: StringBuilder,
+ prefix: StringBuilder,
+) -> StringBuilder =
+ "gleam_stdlib" "iodata_prepend"
+
+/// Append some StringBuilder onto the end of another.
+///
+/// Runs in constant time.
+///
+pub external fn append_builder(
+ to: StringBuilder,
+ suffix: StringBuilder,
+) -> StringBuilder =
+ "gleam_stdlib" "iodata_append"
+
+/// Convert a list of strings into a builder.
+///
+/// Runs in constant time.
+///
+pub external fn from_strings(List(String)) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+/// Joins a list of builders into a single builder.
+///
+/// Runs in constant time.
+///
+pub external fn concat(List(StringBuilder)) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+/// Convert a string into a builder.
+///
+/// Runs in constant time.
+///
+pub external fn from_string(String) -> StringBuilder =
+ "gleam_stdlib" "identity"
+
+/// Turns an `StringBuilder` into a `String`
+///
+/// This function is implemented natively by the virtual machine and is highly
+/// optimised.
+///
+pub external fn to_string(StringBuilder) -> String =
+ "erlang" "iolist_to_binary"
+
+/// Returns the size of the StringBuilder in bytes.
+///
+pub external fn byte_size(StringBuilder) -> Int =
+ "erlang" "iolist_size"
+
+/// Creates a builder containing the textual representation of a given float.
+///
+pub external fn from_float(Float) -> StringBuilder =
+ "io_lib_format" "fwrite_g"
+
+/// Converts a builder to a new builder where the contents have been
+/// lowercased.
+///
+pub external fn lowercase(StringBuilder) -> StringBuilder =
+ "string" "lowercase"
+
+/// Converts a builder to a new builder where the contents have been
+/// uppercased.
+///
+pub external fn uppercase(StringBuilder) -> StringBuilder =
+ "string" "uppercase"
+
+/// Converts a builder to a new builder with the contents reversed.
+///
+pub external fn reverse(StringBuilder) -> StringBuilder =
+ "string" "reverse"
+
+type Direction {
+ All
+}
+
+external fn erl_split(StringBuilder, String, Direction) -> List(StringBuilder) =
+ "string" "split"
+
+/// Splits a builder on a given pattern into a list of builders.
+///
+pub fn split(iodata: StringBuilder, on pattern: String) -> List(StringBuilder) {
+ erl_split(iodata, pattern, All)
+}
+
+external fn erl_replace(
+ StringBuilder,
+ String,
+ String,
+ Direction,
+) -> StringBuilder =
+ "string" "replace"
+
+/// Replaces all instances of a pattern with a given string substitute.
+///
+pub fn replace(
+ in iodata: StringBuilder,
+ each pattern: String,
+ with substitute: String,
+) -> StringBuilder {
+ erl_replace(iodata, pattern, substitute, All)
+}
+
+/// Compare two builders to determine if they have the same textual content.
+///
+/// Comparing two iodata using the `==` operator may return False even if they
+/// have the same content as they may have been build in different ways, so
+/// using this function is often preferred.
+///
+/// ## Examples
+///
+/// > from_strings(["a", "b"]) == new("ab")
+/// False
+///
+/// > is_equal(from_strings(["a", "b"]), new("ab"))
+/// True
+///
+///
+pub external fn is_equal(StringBuilder, StringBuilder) -> Bool =
+ "string" "equal"
+
+/// Inspect a builder to determine if it is equivalent to an empty string.
+///
+/// ## Examples
+///
+/// > new("ok") |> is_empty
+/// False
+///
+/// > new("") |> is_empty
+/// True
+///
+/// > from_strings([]) |> is_empty
+/// True
+///
+///
+pub external fn is_empty(StringBuilder) -> Bool =
+ "string" "is_empty"
diff --git a/test/gleam/iodata_test.gleam b/test/gleam/iodata_test.gleam
deleted file mode 100644
index bc4fe98..0000000
--- a/test/gleam/iodata_test.gleam
+++ /dev/null
@@ -1,96 +0,0 @@
-import gleam/should
-import gleam/iodata
-
-pub fn iodata_test() {
- let data = iodata.new("ello")
- |> iodata.append(",")
- |> iodata.append(" world!")
- |> iodata.prepend("H")
-
- data
- |> iodata.to_string
- |> should.equal("Hello, world!")
-
- data
- |> iodata.byte_size
- |> should.equal(13)
-
- let data = iodata.new("ello")
- |> iodata.append_iodata(iodata.new(","))
- |> iodata.append_iodata(
- iodata.concat([iodata.new(" wo"), iodata.new("rld!")]),
- )
- |> iodata.prepend_iodata(iodata.new("H"))
-
- data
- |> iodata.to_string
- |> should.equal("Hello, world!")
-
- data
- |> iodata.byte_size
- |> should.equal(13)
-}
-
-pub fn lowercase_test() {
- ["Gleam", "Gleam"]
- |> iodata.from_strings
- |> iodata.lowercase
- |> iodata.to_string
- |> should.equal("gleamgleam")
-}
-
-pub fn uppercase_test() {
- ["Gleam", "Gleam"]
- |> iodata.from_strings
- |> iodata.uppercase
- |> iodata.to_string
- |> should.equal("GLEAMGLEAM")
-}
-
-pub fn split_test() {
- "Gleam,Erlang,Elixir"
- |> iodata.new
- |> iodata.split(",")
- |> should.equal(
- [iodata.new("Gleam"), iodata.new("Erlang"), iodata.new("Elixir")],
- )
-
- ["Gleam, Erl", "ang,Elixir"]
- |> iodata.from_strings
- |> iodata.split(", ")
- |> should.equal(
- [iodata.new("Gleam"), iodata.from_strings(["Erl", "ang,Elixir"])],
- )
-}
-
-pub fn is_equal_test() {
- iodata.new("12")
- |> iodata.is_equal(iodata.from_strings(["1", "2"]))
- |> should.be_true
-
- iodata.new("12")
- |> iodata.is_equal(iodata.new("12"))
- |> should.be_true
-
- iodata.new("12")
- |> iodata.is_equal(iodata.new("2"))
- |> should.be_false
-}
-
-pub fn is_empty_test() {
- iodata.new("")
- |> iodata.is_empty
- |> should.be_true
-
- iodata.new("12")
- |> iodata.is_empty
- |> should.be_false
-
- iodata.from_strings([])
- |> iodata.is_empty
- |> should.be_true
-
- iodata.from_strings(["", ""])
- |> iodata.is_empty
- |> should.be_true
-}
diff --git a/test/gleam/string_builder_test.gleam b/test/gleam/string_builder_test.gleam
new file mode 100644
index 0000000..b2e30cf
--- /dev/null
+++ b/test/gleam/string_builder_test.gleam
@@ -0,0 +1,105 @@
+import gleam/should
+import gleam/string_builder
+
+pub fn string_builder_test() {
+ let data = string_builder.from_string("ello")
+ |> string_builder.append(",")
+ |> string_builder.append(" world!")
+ |> string_builder.prepend("H")
+
+ data
+ |> string_builder.to_string
+ |> should.equal("Hello, world!")
+
+ data
+ |> string_builder.byte_size
+ |> should.equal(13)
+
+ let data = string_builder.from_string("ello")
+ |> string_builder.append_builder(string_builder.from_string(","))
+ |> string_builder.append_builder(
+ string_builder.concat(
+ [string_builder.from_string(" wo"), string_builder.from_string("rld!")],
+ ),
+ )
+ |> string_builder.prepend_builder(string_builder.from_string("H"))
+
+ data
+ |> string_builder.to_string
+ |> should.equal("Hello, world!")
+
+ data
+ |> string_builder.byte_size
+ |> should.equal(13)
+}
+
+pub fn lowercase_test() {
+ ["Gleam", "Gleam"]
+ |> string_builder.from_strings
+ |> string_builder.lowercase
+ |> string_builder.to_string
+ |> should.equal("gleamgleam")
+}
+
+pub fn uppercase_test() {
+ ["Gleam", "Gleam"]
+ |> string_builder.from_strings
+ |> string_builder.uppercase
+ |> string_builder.to_string
+ |> should.equal("GLEAMGLEAM")
+}
+
+pub fn split_test() {
+ "Gleam,Erlang,Elixir"
+ |> string_builder.from_string
+ |> string_builder.split(",")
+ |> should.equal(
+ [
+ string_builder.from_string("Gleam"),
+ string_builder.from_string("Erlang"),
+ string_builder.from_string("Elixir"),
+ ],
+ )
+
+ ["Gleam, Erl", "ang,Elixir"]
+ |> string_builder.from_strings
+ |> string_builder.split(", ")
+ |> should.equal(
+ [
+ string_builder.from_string("Gleam"),
+ string_builder.from_strings(["Erl", "ang,Elixir"]),
+ ],
+ )
+}
+
+pub fn is_equal_test() {
+ string_builder.from_string("12")
+ |> string_builder.is_equal(string_builder.from_strings(["1", "2"]))
+ |> should.be_true
+
+ string_builder.from_string("12")
+ |> string_builder.is_equal(string_builder.from_string("12"))
+ |> should.be_true
+
+ string_builder.from_string("12")
+ |> string_builder.is_equal(string_builder.from_string("2"))
+ |> should.be_false
+}
+
+pub fn is_empty_test() {
+ string_builder.from_string("")
+ |> string_builder.is_empty
+ |> should.be_true
+
+ string_builder.from_string("12")
+ |> string_builder.is_empty
+ |> should.be_false
+
+ string_builder.from_strings([])
+ |> string_builder.is_empty
+ |> should.be_true
+
+ string_builder.from_strings(["", ""])
+ |> string_builder.is_empty
+ |> should.be_true
+}