Skip to content

Commit 4aca745

Browse files
committed
Bitwise int functions
1 parent 979f0d5 commit 4aca745

File tree

3 files changed

+149
-0
lines changed

3 files changed

+149
-0
lines changed

src/gleam/int.gleam

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,3 +800,57 @@ pub fn multiply(a: Int, b: Int) -> Int {
800800
pub fn subtract(a: Int, b: Int) -> Int {
801801
a - b
802802
}
803+
804+
/// Calculates the bitwise AND of its arguments.
805+
pub fn bitwise_and(x: Int, y: Int) -> Int {
806+
do_and(x, y)
807+
}
808+
809+
@external(erlang, "erlang", "band")
810+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_and")
811+
fn do_and(a: Int, b: Int) -> Int
812+
813+
/// Calculates the bitwise NOT of its argument.
814+
pub fn bitwise_not(x: Int) -> Int {
815+
do_not(x)
816+
}
817+
818+
@external(erlang, "erlang", "bnot")
819+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_not")
820+
fn do_not(a: Int) -> Int
821+
822+
/// Calculates the bitwise OR of its arguments.
823+
pub fn bitwise_or(x: Int, y: Int) -> Int {
824+
do_or(x, y)
825+
}
826+
827+
@external(erlang, "erlang", "bor")
828+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_or")
829+
fn do_or(a: Int, b: Int) -> Int
830+
831+
/// Calculates the bitwise XOR of its arguments.
832+
pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int {
833+
do_exclusive_or(x, y)
834+
}
835+
836+
@external(erlang, "erlang", "bxor")
837+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or")
838+
fn do_exclusive_or(a: Int, b: Int) -> Int
839+
840+
/// Calculates the result of an arithmetic left bitshift.
841+
pub fn bitwise_shift_left(x: Int, y: Int) -> Int {
842+
do_shift_left(x, y)
843+
}
844+
845+
@external(erlang, "erlang", "bsl")
846+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left")
847+
fn do_shift_left(a: Int, b: Int) -> Int
848+
849+
/// Calculates the result of an arithmetic right bitshift.
850+
pub fn bitwise_shift_right(x: Int, y: Int) -> Int {
851+
do_shift_right(x, y)
852+
}
853+
854+
@external(erlang, "erlang", "bsr")
855+
@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right")
856+
fn do_shift_right(a: Int, b: Int) -> Int

src/gleam_stdlib.mjs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,3 +752,32 @@ function try_get_field(value, field, or_else) {
752752
export function byte_size(string) {
753753
return new TextEncoder().encode(string).length;
754754
}
755+
756+
// In Javascript bitwise operations convert numbers to a sequence of 32 bits
757+
// while Erlang uses arbitrary precision.
758+
// To get around this problem and get consistent results use BigInt and then
759+
// downcast the value back to a Number value.
760+
761+
export function bitwise_and(x, y) {
762+
return Number(BigInt(x) & BigInt(y));
763+
}
764+
765+
export function bitwise_not(x) {
766+
return Number(~BigInt(x));
767+
}
768+
769+
export function bitwise_or(x, y) {
770+
return Number(BigInt(x) | BigInt(y));
771+
}
772+
773+
export function bitwise_exclusive_or(x, y) {
774+
return Number(BigInt(x) ^ BigInt(y));
775+
}
776+
777+
export function bitwise_shift_left(x, y) {
778+
return Number(BigInt(x) << BigInt(y));
779+
}
780+
781+
export function bitwise_shift_right(x, y) {
782+
return Number(BigInt(x) >> BigInt(y));
783+
}

test/gleam/int_test.gleam

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,3 +556,69 @@ pub fn subtract_test() {
556556
|> int.subtract(2, _)
557557
|> should.equal(-1)
558558
}
559+
560+
pub fn and_test() {
561+
int.bitwise_and(9, 3)
562+
|> should.equal(1)
563+
564+
// To check compatibility with JavaScript, try a 32 bit unsigned integer
565+
// (signed integers are in the range -2147483648 to +2147483647, while
566+
// 32 bit unsigned integers are in the range 0 to +4294967295).
567+
int.bitwise_and(2_147_483_648, 2_147_483_648)
568+
|> should.equal(2_147_483_648)
569+
}
570+
571+
pub fn not_test() {
572+
int.bitwise_not(2)
573+
|> should.equal(-3)
574+
575+
// To check compatibility with JavaScript, try a 32 bit unsigned integer.
576+
int.bitwise_not(2_147_483_648)
577+
|> should.equal(-2_147_483_649)
578+
}
579+
580+
pub fn or_test() {
581+
int.bitwise_or(9, 3)
582+
|> should.equal(11)
583+
584+
// To check compatibility with JavaScript, try a 32 bit unsigned integer.
585+
int.bitwise_or(1, 2_147_483_648)
586+
|> should.equal(2_147_483_649)
587+
}
588+
589+
pub fn exclusive_or_test() {
590+
int.bitwise_exclusive_or(9, 3)
591+
|> should.equal(10)
592+
593+
// To check compatibility with JavaScript, try a 32 bit unsigned integer.
594+
int.bitwise_exclusive_or(0, 2_147_483_648)
595+
|> should.equal(2_147_483_648)
596+
}
597+
598+
pub fn shift_left_test() {
599+
int.bitwise_shift_left(1, 2)
600+
|> should.equal(4)
601+
602+
int.bitwise_shift_left(1, -2)
603+
|> should.equal(0)
604+
605+
int.bitwise_shift_left(-1, 2)
606+
|> should.equal(-4)
607+
608+
int.bitwise_shift_left(-1, -2)
609+
|> should.equal(-1)
610+
}
611+
612+
pub fn shift_right_test() {
613+
int.bitwise_shift_right(1, 2)
614+
|> should.equal(0)
615+
616+
int.bitwise_shift_right(1, -2)
617+
|> should.equal(4)
618+
619+
int.bitwise_shift_right(-1, 2)
620+
|> should.equal(-1)
621+
622+
int.bitwise_shift_right(-1, -2)
623+
|> should.equal(-4)
624+
}

0 commit comments

Comments
 (0)