diff options
author | Louis Pilfold <louis@lpil.uk> | 2020-06-26 17:31:53 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2020-06-30 12:14:27 +0100 |
commit | d90199e49c75d051853af52156ee8adaddc58564 (patch) | |
tree | 63a116d0a011d82bc56e2283a0652e812f35dabd | |
parent | 8dab27e6cd093c509e2ca0379dfd41524edc17dc (diff) | |
download | gleam_stdlib-d90199e49c75d051853af52156ee8adaddc58564.tar.gz gleam_stdlib-d90199e49c75d051853af52156ee8adaddc58564.zip |
BitBuilder
-rw-r--r-- | src/gleam/bit_builder.gleam | 90 | ||||
-rw-r--r-- | src/gleam/bit_string.gleam | 3 | ||||
-rw-r--r-- | test/gleam/bit_string_builder_test.gleam | 58 |
3 files changed, 149 insertions, 2 deletions
diff --git a/src/gleam/bit_builder.gleam b/src/gleam/bit_builder.gleam new file mode 100644 index 0000000..c3c88b0 --- /dev/null +++ b/src/gleam/bit_builder.gleam @@ -0,0 +1,90 @@ +import gleam/bit_string.{BitString} + +/// BitBuilder is a type used for efficiently concatenating bits to create bit +/// strings. +/// +/// If we append one bit string to another the bit 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 bit strings together. +/// +/// BitBuilder is different in that it can be joined together in constant +/// time using minimal memory, and then can be efficiently converted to a +/// bit string using the `to_bit_string` function. +/// +pub external type BitBuilder + +/// Prepend a bit string to the start of a builder. +/// +/// Runs in constant time. +/// +pub external fn prepend(to: BitBuilder, prefix: BitString) -> BitBuilder = + "gleam_stdlib" "iodata_prepend" + +/// Append a bit string to the end of a builder. +/// +/// Runs in constant time. +/// +pub external fn append(to: BitBuilder, suffix: BitString) -> BitBuilder = + "gleam_stdlib" "iodata_append" + +/// Prepend a builder onto the start of another. +/// +/// Runs in constant time. +/// +pub external fn prepend_builder( + to: BitBuilder, + prefix: BitBuilder, +) -> BitBuilder = + "gleam_stdlib" "iodata_prepend" + +/// Append a builder onto the end of another. +/// +/// Runs in constant time. +/// +pub external fn append_builder( + to: BitBuilder, + suffix: BitBuilder, +) -> BitBuilder = + "gleam_stdlib" "iodata_append" + +/// Prepend a string onto the start of a builder. +/// +/// Runs in constant time. +/// +pub external fn prepend_string(to: BitBuilder, prefix: String) -> BitBuilder = + "gleam_stdlib" "iodata_prepend" + +/// Append a string onto the end of a builder. +/// +/// Runs in constant time. +/// +pub external fn append_string(to: BitBuilder, suffix: String) -> BitBuilder = + "gleam_stdlib" "iodata_append" + +/// Joins a list of builders into a single builders. +/// +/// Runs in constant time. +/// +pub external fn concat(List(BitBuilder)) -> BitBuilder = + "gleam_stdlib" "identity" + +/// Create a new builder from a bit string. +/// +/// Runs in constant time. +/// +pub external fn from_bit_string(BitString) -> BitBuilder = + "gleam_stdlib" "identity" + +/// Turns an builder into a bit string. +/// +/// This function is implemented natively by the virtual machine and is highly +/// optimised. +/// +pub external fn to_bit_string(BitBuilder) -> BitString = + "erlang" "list_to_bitstring" + +/// Returns the size of the builder's content in bytes. +/// +pub external fn byte_size(BitBuilder) -> Int = + "erlang" "iolist_size" diff --git a/src/gleam/bit_string.gleam b/src/gleam/bit_string.gleam index 1176418..99d91b1 100644 --- a/src/gleam/bit_string.gleam +++ b/src/gleam/bit_string.gleam @@ -2,8 +2,7 @@ //// The BitString type should be used instead of a String type when not utf8 //// encoded. -// TODO: determine which of these functions once we have bit string syntax -pub external type BitString +pub type BitString = BitString /// Convert a utf8 String type into a raw BitString type. /// diff --git a/test/gleam/bit_string_builder_test.gleam b/test/gleam/bit_string_builder_test.gleam new file mode 100644 index 0000000..43e010a --- /dev/null +++ b/test/gleam/bit_string_builder_test.gleam @@ -0,0 +1,58 @@ +import gleam/should +import gleam/bit_builder + +pub fn builder_test() { + let data = bit_builder.from_bit_string(<<1>>) + |> bit_builder.append(<<2>>) + |> bit_builder.append(<<3>>) + |> bit_builder.prepend(<<0>>) + + data + |> bit_builder.to_bit_string + |> should.equal(<<0, 1, 2, 3>>) + + data + |> bit_builder.byte_size + |> should.equal(4) +} + +pub fn builder_with_strings_test() { + let data = bit_builder.from_bit_string(<<1>>) + |> bit_builder.append_string("2") + |> bit_builder.append_string("3") + |> bit_builder.prepend_string("0") + + data + |> bit_builder.to_bit_string + |> should.equal(<<"0":utf8, 1, "2":utf8, "3":utf8>>) + + data + |> bit_builder.byte_size + |> should.equal(4) +} + +pub fn builder_with_builders_test() { + let data = bit_builder.from_bit_string(<<1>>) + |> bit_builder.append_builder(bit_builder.from_bit_string(<<2>>)) + |> bit_builder.append_builder(bit_builder.from_bit_string(<<3>>)) + |> bit_builder.prepend_builder(bit_builder.from_bit_string(<<0>>)) + + data + |> bit_builder.to_bit_string + |> should.equal(<<0, 1, 2, 3>>) + + data + |> bit_builder.byte_size + |> should.equal(4) +} + +pub fn concat_test() { + [ + bit_builder.from_bit_string(<<1, 2>>), + bit_builder.from_bit_string(<<3, 4>>), + bit_builder.from_bit_string(<<5, 6>>), + ] + |> bit_builder.concat + |> bit_builder.to_bit_string + |> should.equal(<<1, 2, 3, 4, 5, 6>>) +} |