Skip to content

Commit bc26ffc

Browse files
committed
Support BigInt hash values.
1 parent 2f0e3bb commit bc26ffc

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

Sources/LispKit/Primitives/HashTableLibrary.swift

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//
2020

2121
import Foundation
22+
import NumberKit
2223

2324
///
2425
/// Hashtable library: based on R6RS spec.
@@ -505,10 +506,23 @@ public final class HashTableLibrary: NativeLibrary {
505506
return .fixnum(Int64(expr.hashValue))
506507
}
507508

509+
private func bucket(_ hval: Expr, _ numBuckets: Int) throws -> Int {
510+
switch hval {
511+
case .fixnum(let num):
512+
return Int(num %% Int64(numBuckets))
513+
case .bignum(let num):
514+
let n = BigInt(numBuckets)
515+
let rem = num % n
516+
return Int(rem.isNegative ? (rem + n).intValue! : rem.intValue!)
517+
default:
518+
throw RuntimeError.type(hval, expected: [.exactIntegerType])
519+
}
520+
}
521+
508522
private func hBuckets(_ expr: Expr, hval: Expr?) throws -> Expr {
509523
let map = try expr.asHashTable()
510-
if let hashValue = try hval?.asInt64() {
511-
return map.bucketList(Int(hashValue %% Int64(map.bucketCount)))
524+
if let hashValue = hval {
525+
return map.bucketList(try self.bucket(hashValue, map.bucketCount))
512526
} else {
513527
return map.bucketList()
514528
}
@@ -521,16 +535,15 @@ public final class HashTableLibrary: NativeLibrary {
521535
if !key.isAtom || !value.isAtom {
522536
self.context.objects.manage(map)
523537
}
524-
map.add(Int(try hval.asInt64() %% Int64(map.bucketCount)), key, value)
538+
map.add(try self.bucket(hval, map.bucketCount), key, value)
525539
return .void
526540
}
527541

528542
private func hBucketRepl(_ expr: Expr, hval: Expr, bucket: Expr) throws -> Expr {
529543
guard case .table(let map) = expr else {
530544
throw RuntimeError.type(expr, expected: [.tableType])
531545
}
532-
map.replace(Int(try hval.asInt64() %% Int64(map.bucketCount)), bucket)
546+
map.replace(try self.bucket(hval, map.bucketCount), bucket)
533547
return .void
534548
}
535549
}
536-

Sources/LispKit/Primitives/MathLibrary.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public final class MathLibrary: NativeLibrary {
162162
self.define(Procedure("fxmin", self.fxMin))
163163
self.define(Procedure("fxmax", self.fxMax))
164164
self.define(Procedure("fxrandom", self.fxRandom))
165+
self.define(Procedure("integer->fx", self.integerToFx))
165166
self.define(Procedure("fixnum-width", self.fixnumWidth))
166167
self.define(Procedure("least-fixnum", self.leastFixnum))
167168
self.define(Procedure("greatest-fixnum", self.greatestFixnum))
@@ -1727,6 +1728,19 @@ public final class MathLibrary: NativeLibrary {
17271728
return .fixnum(Int64.random(min: min, max: max))
17281729
}
17291730

1731+
private static let maxFx = BigInt(Int64.max) + 1
1732+
1733+
private func integerToFx(_ expr: Expr) throws -> Expr {
1734+
switch expr {
1735+
case .fixnum(_):
1736+
return expr
1737+
case .bignum(let num):
1738+
return .fixnum((num % MathLibrary.maxFx).intValue!)
1739+
default:
1740+
throw RuntimeError.type(expr, expected: [.exactIntegerType])
1741+
}
1742+
}
1743+
17301744
private func fixnumWidth() -> Expr {
17311745
return .fixnum(Int64(Int64.bitWidth))
17321746
}

Sources/LispKit/Resources/Libraries/srfi/113.sld

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,10 +1421,9 @@
14211421

14221422
;; Hash over sobs
14231423
(define (sob-hash sob)
1424-
(let* ((ht (sob-hash-table sob))
1425-
(hash (comparator-hash-function (sob-comparator sob))))
1424+
(let* ((hash (comparator-hash-function (sob-comparator sob))))
14261425
(sob-fold
1427-
(lambda (element result) (+ (hash element) result))
1426+
(lambda (element result) (fx+ (integer->fx (hash element)) result))
14281427
5381
14291428
sob)))
14301429

0 commit comments

Comments
 (0)