Skip to content

Commit 8536d3c

Browse files
committed
Add bit_array.split_once
1 parent f690a8e commit 8536d3c

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

Diff for: src/gleam/bit_array.gleam

+18
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,24 @@ pub fn slice(
5959
take length: Int,
6060
) -> Result(BitArray, Nil)
6161

62+
/// Splits a bit array into two parts at the location of the pattern.
63+
///
64+
/// The result will not include the pattern, and returns an error if the
65+
/// pattern is not found.
66+
///
67+
/// ## Examples
68+
///
69+
/// ```gleam
70+
/// split_once(from: <<1, 2, 3>>, on: <<2>>)
71+
/// // -> Ok(#(<<1>>, <<3>>))
72+
/// ```
73+
@external(erlang, "gleam_stdlib", "bit_array_split_once")
74+
@external(javascript, "../gleam_stdlib.mjs", "bit_array_split_once")
75+
pub fn split_once(
76+
from bits: BitArray,
77+
on pattern: BitArray,
78+
) -> Result(#(BitArray, BitArray), Nil)
79+
6280
/// Tests to see whether a bit array is valid UTF-8.
6381
///
6482
pub fn is_utf8(bits: BitArray) -> Bool {

Diff for: src/gleam_stdlib.erl

+11-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
inspect/1, float_to_string/1, int_from_base_string/2,
1515
utf_codepoint_list_to_string/1, contains_string/2, crop_string/2,
1616
base16_encode/1, base16_decode/1, string_replace/3, slice/3,
17-
bit_array_to_int_and_size/1, bit_array_pad_to_bytes/1
17+
bit_array_to_int_and_size/1, bit_array_pad_to_bytes/1, bit_array_split_once/2
1818
]).
1919

2020
%% Taken from OTP's uri_string module
@@ -231,6 +231,16 @@ bit_array_slice(Bin, Pos, Len) ->
231231
catch error:badarg -> {error, nil}
232232
end.
233233

234+
bit_array_split_once(Bin, Sub) ->
235+
try
236+
case binary:split(Bin, [Sub]) of
237+
[<<>>, <<>>] -> {error, nil};
238+
[Part1, Part2] -> {ok, {Part1, Part2}};
239+
_ -> {error, nil}
240+
end
241+
catch error:badarg -> {error, nil}
242+
end.
243+
234244
base_decode64(S) ->
235245
try {ok, base64:decode(S)}
236246
catch error:_ -> {error, nil}

Diff for: src/gleam_stdlib.mjs

+24
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,30 @@ export function bit_array_slice(bits, position, length) {
425425
return new Ok(new BitArray(buffer));
426426
}
427427

428+
export function bit_array_split_once(bits, pattern) {
429+
try {
430+
if (!(bits instanceof BitArray) || !(pattern instanceof BitArray) || pattern.buffer.length < 1 || pattern.buffer.length >= bits.buffer.length) {
431+
return new Error(Nil);
432+
}
433+
434+
let i = 0;
435+
const n = bits.buffer.length - pattern.buffer.length + 1;
436+
437+
find: for (; i < n; i++) {
438+
for (let j = 0; j < pattern.buffer.length; j++) {
439+
if (bits.buffer[i + j] !== pattern.buffer[j]) continue find;
440+
}
441+
const before = bits.buffer.slice(0, i);
442+
const after = bits.buffer.slice(i + pattern.buffer.length);
443+
return new Ok([new BitArray(before), new BitArray(after)]);
444+
}
445+
446+
return new Error(Nil);
447+
} catch (e) {
448+
return new Error(Nil);
449+
}
450+
}
451+
428452
export function codepoint(int) {
429453
return new UtfCodepoint(int);
430454
}

Diff for: test/gleam/bit_array_test.gleam

+35
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,41 @@ pub fn slice_erlang_only_test() {
202202
|> should.equal(Error(Nil))
203203
}
204204

205+
pub fn split_once_test() {
206+
<<"hello":utf8>>
207+
|> bit_array.split_once(<<"l":utf8>>)
208+
|> should.equal(Ok(#(<<"he":utf8>>, <<"lo":utf8>>)))
209+
210+
<<"hello":utf8>>
211+
|> bit_array.split_once(<<"o":utf8>>)
212+
|> should.equal(Ok(#(<<"hell":utf8>>, <<>>)))
213+
214+
<<"hello":utf8>>
215+
|> bit_array.split_once(<<"h":utf8>>)
216+
|> should.equal(Ok(#(<<>>, <<"ello":utf8>>)))
217+
218+
<<"hello":utf8>>
219+
|> bit_array.split_once(<<1>>)
220+
|> should.equal(Error(Nil))
221+
222+
<<"hello":utf8>>
223+
|> bit_array.split_once(<<"":utf8>>)
224+
|> should.equal(Error(Nil))
225+
226+
<<"hello":utf8>>
227+
|> bit_array.split_once(<<"hello":utf8>>)
228+
|> should.equal(Error(Nil))
229+
}
230+
231+
// This test is target specific since it's using non byte-aligned BitArrays
232+
// and those are not supported on the JavaScript target.
233+
@target(erlang)
234+
pub fn split_once_erlang_only_test() {
235+
<<0, 1, 2:7>>
236+
|> bit_array.split_once(<<1>>)
237+
|> should.equal(Error(Nil))
238+
}
239+
205240
pub fn to_string_test() {
206241
<<>>
207242
|> bit_array.to_string

0 commit comments

Comments
 (0)