aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gleam/bit_array.gleam25
-rw-r--r--src/gleam_stdlib.erl7
-rw-r--r--test/gleam/bit_array_test.gleam37
3 files changed, 52 insertions, 17 deletions
diff --git a/src/gleam/bit_array.gleam b/src/gleam/bit_array.gleam
index af78fcc..909d9f1 100644
--- a/src/gleam/bit_array.gleam
+++ b/src/gleam/bit_array.gleam
@@ -205,20 +205,23 @@ fn do_inspect(input: BitArray, accumulator: String) -> String {
/// ```
///
pub fn compare(first: BitArray, second: BitArray) -> order.Order {
- do_compare(first, second, 0)
-}
-
-fn do_compare(first: BitArray, second: BitArray, index: Int) -> order.Order {
- case slice(first, index, 1), slice(second, index, 1) {
- Ok(<<first_byte>>), Ok(<<second_byte>>) ->
+ case first, second {
+ <<first_byte, first_rest:bits>>, <<second_byte, second_rest:bits>> ->
int.compare(first_byte, second_byte)
- |> order.lazy_break_tie(fn() { do_compare(first, second, index + 1) })
+ |> order.lazy_break_tie(fn() { compare(first_rest, second_rest) })
+ <<>>, <<>> -> order.Eq
// First has more items, example: "AB" > "A":
- Ok(_), Error(_) -> order.Gt
+ _, <<>> -> order.Gt
// Second has more items, example: "A" < "AB":
- Error(_), Ok(_) -> order.Lt
- // Both have the same length, fallback:
- _, _ -> order.Eq
+ <<>>, _ -> order.Lt
+ // This happens when there's unusually sized elements.
+ // Handle these special cases via custom erlang function.
+ // This cannot be reached in JS right now.
+ first, second ->
+ int.compare(bit_array_to_int(first), bit_array_to_int(second))
}
}
+
+@external(erlang, "gleam_stdlib", "bit_array_to_int")
+fn bit_array_to_int(first: BitArray) -> Int
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index 0941a33..96a35b7 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -14,7 +14,7 @@
decode_tuple5/1, decode_tuple6/1, tuple_get/2, classify_dynamic/1, print/1,
println/1, print_error/1, println_error/1, inspect/1, float_to_string/1,
int_from_base_string/2, utf_codepoint_list_to_string/1, contains_string/2,
- crop_string/2, base16_decode/1, string_replace/3, regex_replace/3, slice/3
+ crop_string/2, base16_decode/1, string_replace/3, regex_replace/3, slice/3, bit_array_to_int/1
]).
%% Taken from OTP's uri_string module
@@ -492,6 +492,11 @@ inspect_bit_array(Rest, Acc) ->
Segment = <<X1/binary, ":size(", Size1/binary, ")">>,
inspect_bit_array(<<>>, append_segment(Acc, Segment)).
+bit_array_to_int(A) ->
+ Size = bit_size(A),
+ <<A1:Size>> = A,
+ A1.
+
append_segment(<<"<<">>, Segment) ->
<<"<<", Segment/binary>>;
append_segment(Acc, Segment) ->
diff --git a/test/gleam/bit_array_test.gleam b/test/gleam/bit_array_test.gleam
index 56b6bf5..38dcb2e 100644
--- a/test/gleam/bit_array_test.gleam
+++ b/test/gleam/bit_array_test.gleam
@@ -390,10 +390,25 @@ pub fn compare_utf16_test() {
}
@target(erlang)
+pub fn compare_utf32_test() {
+ bit_array.compare(<<"ABC":utf32>>, <<"ABC":utf32>>)
+ |> should.equal(order.Eq)
+
+ bit_array.compare(<<"ABC":utf32>>, <<"AB":utf32>>)
+ |> should.equal(order.Gt)
+
+ bit_array.compare(<<"A":utf32>>, <<"Z":utf32>>)
+ |> should.equal(order.Lt)
+}
+
+@target(erlang)
pub fn compare_mixed_utfs_test() {
bit_array.compare(<<"A":utf16>>, <<"A":utf8>>)
|> should.equal(order.Lt)
+ bit_array.compare(<<"A":utf32>>, <<"A":utf16>>)
+ |> should.equal(order.Lt)
+
bit_array.compare(<<"A":utf8>>, <<"A":utf16>>)
|> should.equal(order.Gt)
@@ -403,11 +418,20 @@ pub fn compare_mixed_utfs_test() {
bit_array.compare(<<"":utf16>>, <<"A":utf8>>)
|> should.equal(order.Lt)
+ bit_array.compare(<<"":utf32>>, <<"A":utf8>>)
+ |> should.equal(order.Lt)
+
+ bit_array.compare(<<"":utf32>>, <<"A":utf16>>)
+ |> should.equal(order.Lt)
+
bit_array.compare(<<"":utf16>>, <<"":utf8>>)
|> should.equal(order.Eq)
bit_array.compare(<<"":utf8>>, <<"":utf16>>)
|> should.equal(order.Eq)
+
+ bit_array.compare(<<"":utf8>>, <<"":utf32>>)
+ |> should.equal(order.Eq)
}
@target(erlang)
@@ -416,19 +440,22 @@ pub fn compare_different_sizes_test() {
|> should.equal(order.Eq)
bit_array.compare(<<3:5>>, <<4:5>>)
- |> should.equal(order.Eq)
+ |> should.equal(order.Lt)
+
+ bit_array.compare(<<3:7>>, <<4:7>>)
+ |> should.equal(order.Lt)
bit_array.compare(<<5:5>>, <<4:5>>)
- |> should.equal(order.Eq)
+ |> should.equal(order.Gt)
bit_array.compare(<<4:8>>, <<4:5>>)
- |> should.equal(order.Gt)
+ |> should.equal(order.Eq)
bit_array.compare(<<4:5>>, <<4:8>>)
- |> should.equal(order.Lt)
+ |> should.equal(order.Eq)
bit_array.compare(<<0:5>>, <<0:8>>)
- |> should.equal(order.Lt)
+ |> should.equal(order.Eq)
bit_array.compare(<<0:2>>, <<0:1>>)
|> should.equal(order.Eq)