Skip to content

Commit

Permalink
Merge branch 'main' into yuxiang/hashmap-get-or-init
Browse files Browse the repository at this point in the history
  • Loading branch information
bobzhang authored Dec 23, 2024
2 parents d0e1c76 + e106481 commit 40162fc
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 29 deletions.
3 changes: 0 additions & 3 deletions builtin/array.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,6 @@ pub fn clear[T](self : Array[T]) -> Unit {
/// assert_eq!(v2, [4, 5, 6])
/// ```
pub fn map[T, U](self : Array[T], f : (T) -> U) -> Array[U] {
if self.length() == 0 {
return []
}
let arr = Array::make_uninit(self.length())
for i, v in self {
arr.unsafe_set(i, f(v))
Expand Down
7 changes: 7 additions & 0 deletions builtin/array_block.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ test "Array::blit_to - boundary cases" {
inspect!(dst, content="[5, 0, 0, 4, 5]")
}

test "Array::unsafe_blit_fixed" {
let src = FixedArray::make(3, 1) // Create a FixedArray with 3 elements of value 1
let dst = Array::make(5, 0) // Create an Array with 5 elements of value 0
Array::unsafe_blit_fixed(dst, 1, src, 0, 2) // Copy 2 elements from src[0] to dst[1]
inspect!(dst, content="[0, 1, 1, 0, 0]")
}

// test "Array::blit_to - invalid cases" {
// let src = [1, 2, 3, 4, 5]
// let dst = [0, 0, 0, 0, 0]
Expand Down
18 changes: 18 additions & 0 deletions builtin/array_wbtest.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2024 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 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.

test {
let empty : Array[Unit] = Array::make_uninit(0)
inspect!(empty, content="[]")
}
28 changes: 24 additions & 4 deletions builtin/bigint_js.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,32 @@ pub extern "js" fn op_mod(self : BigInt, other : BigInt) -> BigInt =
#|(x, y) => x % y

///|
pub extern "js" fn pow(
extern "js" fn modpow_ffi(
self : BigInt,
other : BigInt,
modulus~ : BigInt = 1N
exponent : BigInt,
modulus : BigInt
) -> BigInt =
#|(x, y, z) => (x ** y) % z
#|(x, y, z) => x ** y % z

///|
extern "js" fn pow_ffi(self : BigInt, exponent : BigInt) -> BigInt =
#|(x, y) => x ** y

///|
pub fn pow(self : BigInt, exponent : BigInt, modulus? : BigInt) -> BigInt {
if exponent < 0 {
abort("negative exponent")
}
match modulus {
Some(modulus) =>
if modulus <= 0 {
abort("non-positive modulus")
} else {
modpow_ffi(self, exponent, modulus)
}
None => pow_ffi(self, exponent)
}
}

///|
extern "js" fn to_byte(self : BigInt) -> Byte =
Expand Down
83 changes: 66 additions & 17 deletions builtin/bigint_nonjs.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -772,29 +772,78 @@ fn max[T : Compare](a : T, b : T) -> T {
}

///|
/// Compute the power of a BigInt to another BigInt.
/// Computes the result of raising a `BigInt` to the power of another `BigInt`,
/// with an optional modulus.
///
/// When a modulus is provided, computes the modular exponentiation using the
/// square-and-multiply algorithm. This is particularly useful in cryptographic
/// applications where direct exponentiation would result in numbers too large to
/// handle efficiently.
///
/// Parameters:
///
/// * `self` : The base number to be raised to a power.
/// * `exp` : The exponent (must be non-negative).
/// * `modulus` : Optional modulus for modular exponentiation (must be positive
/// if provided).
///
/// Returns the result of the exponentiation, or the result modulo `modulus` if a
/// modulus is provided.
///
/// Throws:
///
/// * Aborts if the exponent is negative.
/// * Aborts if the provided modulus is zero or negative.
///
/// Example:
///
/// ```moonbit
/// test "BigInt::pow" {
/// let base = BigInt::from_string("3")
/// let exp = BigInt::from_string("4")
/// inspect!(base.pow(exp), content="81")
/// inspect!(base.pow(exp, modulus=BigInt::from_string("10")), content="1")
/// }
///
/// Optionally takes a modulus BigInt.
///
/// The exponent must be non-negative, and modulus must be positive.
pub fn pow(self : BigInt, exp : BigInt, modulus~ : BigInt = one) -> BigInt {
/// test "panic BigInt::pow/negative_exponent" {
/// let base = BigInt::from_string("3")
/// let exp = BigInt::from_string("-1")
/// ignore(base.pow(exp))
/// }
/// ```
pub fn pow(self : BigInt, exp : BigInt, modulus? : BigInt) -> BigInt {
if exp.sign == Negative {
abort("negative exponent")
}
if modulus.is_zero() || modulus.sign == Negative {
abort("modulus non-positive")
}
let mut result = 1N
let mut base = self
let mut exp = exp
while exp > 0N {
if exp % 2N == 1N {
result = result * base % modulus
match modulus {
None => {
let mut result = 1N
let mut base = self
let mut exp = exp
while exp > 0 {
if exp % 2 == 1 {
result = result * base
}
base = base * base
exp = exp / 2
}
result
}
Some(modulus) => {
guard not(modulus.is_zero() || modulus.sign == Negative)
let mut result = 1N
let mut base = self
let mut exp = exp
while exp > 0 {
if exp % 2 == 1 {
result = result * base % modulus
}
base = base * base % modulus
exp = exp / 2
}
result
}
base = base * base % modulus
exp = exp / 2N
}
result
}

///|
Expand Down
4 changes: 4 additions & 0 deletions builtin/bigint_wbtest.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -723,4 +723,8 @@ test "pow" {
inspect!(4N.pow(13N, modulus=497N), content="445")
inspect!(65N.pow(17, modulus=3233), content="2790")
inspect!(2790N.pow(413, modulus=3233), content="65")
inspect!(
2790N.pow(413),
content="10827693458027068918752254513689369927451498632867702850871449492721716762882046359646654407147290095143376244612860740505063304616869045757879636651922242895944635094287526023557872050108996014618928707382416906723717536207944990935946477343103732942220495426003253324856391048675505527041527544249845903325107575822015010197006079682477544271998209608154757421132764034059289159228295810448568286783859864141487725512980856505994152145510660350938086763233208252511256291934375881870590480237727775536326670654123168787472077359939510018827829233028430183558108518520524567765780717109616748933630364200317687291046055118737587697510939517252245710306646155772831436013971724481443654932630319085588147436112198934867224850036968074130558127066188475740553149587714112808551835880666012903651859580234129805580074844684526620091506655345299434455806896837926335229779632528684030400890708579038639280240022309690038032176604539091205540422068492362106868171343650410145963283813864374487990607671475570427243900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
)
}
2 changes: 1 addition & 1 deletion builtin/builtin.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl BigInt {
op_shl(Self, Int) -> Self
op_shr(Self, Int) -> Self
op_sub(Self, Self) -> Self
pow(Self, Self, modulus~ : Self = ..) -> Self
pow(Self, Self, modulus? : Self) -> Self
shl(Self, Int) -> Self //deprecated
shr(Self, Int) -> Self //deprecated
to_hex(Self, uppercase~ : Bool = ..) -> String
Expand Down
16 changes: 12 additions & 4 deletions hashmap/hashmap.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,19 @@ pub fn T::from_array[K : Hash + Eq, V](arr : Array[(K, V)]) -> T[K, V] {
/// Set a key-value pair into hash map.
/// @alert unsafe "Panic if the hash map is full."
pub fn set[K : Hash + Eq, V](self : T[K, V], key : K, value : V) -> Unit {
self.set_with_hash(key, value, key.hash())
}

///|
fn set_with_hash[K : Eq, V](
self : T[K, V],
key : K,
value : V,
hash : Int
) -> Unit {
if self.size >= self.capacity / 2 {
self.grow()
}
let hash = key.hash()
for idx = hash & (self.capacity - 1), entry = { psl: 0, hash, key, value } {
match self.entries[idx] {
None => {
Expand Down Expand Up @@ -220,16 +229,15 @@ fn shift_back[K : Hash, V](self : T[K, V], start_index : Int) -> Unit {
}

///|
// TODO: this could be further optimized
fn grow[K : Hash + Eq, V](self : T[K, V]) -> Unit {
fn grow[K : Eq, V](self : T[K, V]) -> Unit {
let old_entries = self.entries
let new_capacity = self.capacity << 1
self.entries = FixedArray::make(new_capacity, None)
self.capacity = new_capacity
self.size = 0
for i = 0; i < old_entries.length(); i = i + 1 {
match old_entries[i] {
Some({ key, value, .. }) => self.set(key, value)
Some({ key, value, hash, .. }) => self.set_with_hash(key, value, hash)
None => ()
}
}
Expand Down

0 comments on commit 40162fc

Please sign in to comment.