Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stdlib] Add bin() builtin function #2603

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ what we publish.
- Added the `Indexer` trait to denote types that implement the `__index__()`
method which allow these types to be accepted in common `__getitem__` and
`__setitem__` implementations, as well as allow a new builtin `index` function
to be called on them. For example:
to be called on them.
([PR #2685](https://github.com/modularml/mojo/pull/2685) by
[@bgreni](https://github.com/bgreni))
For example:

```mojo
@value
Expand All @@ -275,6 +278,10 @@ what we publish.
trailing whitespaces. ([PR #2683](https://github.com/modularml/mojo/pull/2683)
by [@fknfilewalker](https://github.com/fknfilewalker))

- Added the `bin()` builtin function to convert integral types into their binary string representation.
([PR #2603](https://github.com/modularml/mojo/pull/2603) by
[@bgreni](https://github.com/bgreni))

### 🦋 Changed

- The `let` keyword has been completely removed from the language. We previously
Expand Down
86 changes: 86 additions & 0 deletions stdlib/src/builtin/bin.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# ===----------------------------------------------------------------------=== #
bgreni marked this conversation as resolved.
Show resolved Hide resolved
# Copyright (c) 2024, Modular Inc. All rights reserved.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions:
# https://llvm.org/LICENSE.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===----------------------------------------------------------------------=== #
"""Implements the `bin()` function

These are Mojo built-ins, so you don't need to import them.
"""


# Need this until we have constraints to stop
# the compiler from matching this directly
# to bin[type: DType](num: Scalar[type])
@always_inline("nodebug")
fn bin(b: Scalar[DType.bool]) -> String:
"""Returns the binary representation of a scalar bool.

Args:
b: A scalar bool value.

Returns:
The binary string representation of b.
"""
return bin(index(b))


fn bin[type: DType](num: Scalar[type]) -> String:
bgreni marked this conversation as resolved.
Show resolved Hide resolved
"""Return the binary string representation an integral value.

```mojo
print(bin(123))
print(bin(-123))
```
```plaintext
'0b1111011'
'-0b1111011'
```

Parameters:
type: The data type of the integral scalar.

Args:
num: An integral scalar value.

Returns:
The binary string representation of num.
"""
constrained[type.is_integral(), "Expected integral value"]()
alias BIN_PREFIX = "0b"

if num == 0:
return BIN_PREFIX + "0"

# TODD: pre-allocate string size when #2194 is resolved
var result = String()
bgreni marked this conversation as resolved.
Show resolved Hide resolved
var cpy = abs(num)
while cpy > 0:
result += str(cpy & 1)
cpy = cpy >> 1

result = BIN_PREFIX + result[::-1]
return "-" + result if num < 0 else result


@always_inline("nodebug")
fn bin[T: Indexer](num: T) -> String:
"""Returns the binary representation of an indexer type.

Parameters:
T: The Indexer type.

Args:
num: An indexer value.

Returns:
The binary string representation of num.
"""
return bin(Scalar[DType.index](index(num)))
2 changes: 1 addition & 1 deletion stdlib/src/builtin/int.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ trait Indexer:


@always_inline("nodebug")
fn index[T: Indexer](idx: T) -> Int:
fn index[T: Indexer](idx: T, /) -> Int:
"""Returns the value of `__index__` for the given value.
Parameters:
Expand Down
55 changes: 55 additions & 0 deletions stdlib/test/builtin/test_bin.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ===----------------------------------------------------------------------=== #
# Copyright (c) 2024, Modular Inc. All rights reserved.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions:
# https://llvm.org/LICENSE.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===----------------------------------------------------------------------=== #
# RUN: %mojo %s

from testing import assert_equal


@value
struct Ind(Indexer):
fn __index__(self) -> Int:
return 1


def test_bin_scalar():
assert_equal(bin(Int8(2)), "0b10")
assert_equal(bin(Int32(123)), "0b1111011")
assert_equal(bin(Int32(-123)), "-0b1111011")
assert_equal(bin(Scalar[DType.bool](True)), "0b1")
assert_equal(bin(Scalar[DType.bool](False)), "0b0")


def test_bin_int():
assert_equal(bin(0), "0b0")
assert_equal(bin(1), "0b1")
assert_equal(bin(-1), "-0b1")
assert_equal(bin(4), "0b100")
assert_equal(bin(Int(-4)), "-0b100")
assert_equal(bin(389703), "0b1011111001001000111")
assert_equal(bin(-10), "-0b1010")


def test_bin_bool():
assert_equal(bin(True), "0b1")
assert_equal(bin(False), "0b0")


def test_indexer():
assert_equal(bin(Ind()), "0b1")


def main():
test_bin_scalar()
test_bin_int()
test_bin_bool()
test_indexer()
Loading