UNPKG

as-soroban-sdk

Version:

AssemblyScript SDK for writing contracts for Soroban.

599 lines (559 loc) 18.2 kB
// Offers arithmetic helper functions for positive I128Val and U128Val host values. // Supports only positive values. Uses u128_math.ts => bitwise operations. // If you are looking for I128Val and U128Val arithmetic helpers using // host functions see: arithm128.ts. import * as context from "./context"; import { ge, gt, le, lt, eq, isZero, add, __hi, sub, mul, div, muldiv, sqrt, pow, ord } from "./u128_math"; import { I128Val, U128Val, fromI128Pieces, fromI128Small, fromU128Pieces, fromU128Small, isI128Object, isI128Small, isU128Object, isU128Small, toI128High64, toI128Low64, toI128Small, toU128High64, toU128Low64, toU128Small } from "./value"; /** * Checks if a given I128Val is negative. Traps if not I128Val (I128Object or I128SmallVal) * @param value the I128Val to check. * @returns true if negative otherwise false. */ export function isNegative(value:I128Val) : bool { if (isI128Small(value)) { return toI128Small(value) < 0; } else if (isI128Object(value)) { return toI128High64(value) < 0; } else { context.fail(); return 0; } } /*export function isNegative(value:I128Val) : bool { let alo = getI128Parts(value); return lt(alo, __reshi, 0, 0); }*/ /** * Checks if first given I128Val is lower then - operator('<') - second I128Val. * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns true if a < b */ export function i128lt(a:I128Val, b:I128Val) : bool { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return lt(alo, ahi, blo, bhi); } /** * Checks if first given I128Val is lower or equal - operator('<=') - second I128Val. * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns true if a <= b */ export function i128le(a:I128Val, b:I128Val) : bool { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return le(alo, ahi, blo, bhi); } /** * Checks if first given I128Val is equal - operator('==') - second I128Val. * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns true if a == b */ export function i128eq(a:I128Val, b:I128Val) : bool { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return eq(alo, ahi, blo, bhi); } /** * Checks if first given I128Val is greater then - operator('>') - second I128Val. * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns true if a > b */ export function i128gt(a:I128Val, b:I128Val) : bool { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return gt(alo, ahi, blo, bhi); } /** * Checks if first given I128Val is greater or equal - operator('>=') - second I128Val. * Supports positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns true if a >= b */ export function i128ge(a:I128Val, b:I128Val) : bool { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return ge(alo, ahi, blo, bhi); } /** * Get ordering. * if a > b then result is 1 * if a < b then result is -1 * if a = b then result is 0 * Supports positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns order */ export function i128ord(a:I128Val, b:I128Val) : i32 { let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; return ord(alo, ahi, blo, bhi); } /** * Checks if the given I128Val is zero. * Traps if not I128Val (I128Object or I128SmallVal) value. * @param value I128Val to check. * @returns true if zero */ export function i128isZero(value:I128Val) : bool { let vlo = getI128Parts(value); let vhi = __reshi; return isZero(vlo, vhi); } /** * Checks if first given U128Val is lower then - operator('<') - second U128Val. * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns true if a < b */ export function u128lt(a:U128Val, b:U128Val) : bool { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return lt(alo, ahi, blo, bhi); } /** * Checks if first given U128Val is lower or equal - operator('<=') - second U128Val. * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns true if a <= b */ export function u128eq(a:U128Val, b:U128Val) : bool { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return eq(alo, ahi, blo, bhi); } /** * Checks if first given U128Val is equal - operator('==') - second U128Val. * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns true if a == b */ export function u128le(a:U128Val, b:U128Val) : bool { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return le(alo, ahi, blo, bhi); } /** * Checks if first given U128Val is greater then - operator('>') - second U128Val. * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns true if a > b */ export function u128gt(a:U128Val, b:U128Val) : bool { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return gt(alo, ahi, blo, bhi); } /** * Checks if first given U128Val is greater then - operator('>=') - second U128Val. * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns true if a >= b */ export function u128ge(a:U128Val, b:U128Val) : bool { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return ge(alo, ahi, blo, bhi); } /** * Get ordering. * if a > b then result is 1 * if a < b then result is -1 * if a = b then result is 0 * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns order. */ export function u128ord(a:U128Val, b:U128Val) : i32 { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; return ord(alo, ahi, blo, bhi); } /** * Checks if the given U128Val is zero. * Traps if not U128Val (U128Object or U128SmallVal) value. * @param value U128Val to check. * @returns true if zero */ export function u128isZero(value:U128Val) : bool { let vlo = getU128Parts(value); let vhi = __reshi; return isZero(vlo, vhi); } /** * Adds two positive i128 numbers (a + b). * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns I128Val as the result of a + b */ export function i128add(a:I128Val, b:I128Val) : I128Val { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; let reslo = add(alo, ahi, blo, bhi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Adds two u128 numbers (a + b). * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns U128Val as the result of a + b */ export function u128add(a:U128Val, b:U128Val) : U128Val { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; let reslo = add(alo, ahi, blo, bhi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Substraction of two positive i128 numbers (a - b). * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns I128Val as the result of a - b */ export function i128sub(a:I128Val, b:I128Val) : I128Val { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; let reslo = sub(alo, ahi, blo, bhi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Substraction of two u128 numbers (a - b). * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns U128Val as the result of a - b */ export function u128sub(a:U128Val, b:U128Val) : U128Val { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; let reslo = sub(alo, ahi, blo, bhi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Multipies two positive i128 numbers (a * b). * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns I128Val as the result of a * b */ export function i128mul(a:I128Val, b:I128Val) : I128Val { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; let reslo = mul(alo, ahi, blo, bhi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Multipies two u128 numbers (a - b). * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns U128Val as the result of a * b */ export function u128mul(a:U128Val, b:U128Val) : U128Val { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; let reslo = mul(alo, ahi, blo, bhi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Devides two positive i128 numbers (a / b). * Supports only positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if one or both of the given values are negative. To avoid, use "isNegative()". * @param a first I128Val. * @param b second I128Val. * @returns I128Val as the result of a / b */ export function i128div(a:I128Val, b:I128Val) : I128Val { if (isNegative(a) || isNegative(b)) { context.fail(); } let alo = getI128Parts(a); let ahi = __reshi; let blo = getI128Parts(b); let bhi = __reshi; let reslo = div(alo, ahi, blo, bhi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Devides two u128 numbers (a / b). * Traps if not U128Val (U128Object or U128SmallVal) values. * @param a first U128Val. * @param b second U128Val. * @returns U128Val as the result of a / b */ export function u128div(a:U128Val, b:U128Val) : U128Val { let alo = getU128Parts(a); let ahi = __reshi; let blo = getU128Parts(b); let bhi = __reshi; let reslo = div(alo, ahi, blo, bhi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Multiplies and devides i128 numbers without overflow in multiplication part (number * numerator / denominator). * Supports positive values. * Traps if not I128Val (I128Object or I128SmallVal) values. * Traps if any of the given values are negative. To avoid, use "isNegative()". * @param number number to multiply with numerator I128Val. * @param numerator numerator to multiply with number I128Val. * @param denominator I128Val. * @returns I128Val as the result of number * numerator / denominator. */ export function i128muldiv(number:I128Val, numerator:I128Val, denominator: I128Val) : I128Val { if (isNegative(number) || isNegative(numerator) || isNegative(denominator)) { context.fail(); } let alo = getI128Parts(number); let ahi = __reshi; let blo = getI128Parts(numerator); let bhi = __reshi; let clo = getI128Parts(denominator); let chi = __reshi; let reslo = muldiv(alo, ahi, blo, bhi, clo, chi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Multiplies and devides u128 numbers without overflow in multiplication part (number * numerator / denominator). * Traps if not U128Val (U128Object or U128SmallVal) values. * @param number number to multiply with numerator U128Val. * @param numerator numerator to multiply with number U128Val. * @param denominator U128Val. * @returns U128Val as the result of number * numerator / denominator. */ export function u128muldiv(number:U128Val, numerator:U128Val, denominator: U128Val) : U128Val { let alo = getU128Parts(number); let ahi = __reshi; let blo = getU128Parts(numerator); let bhi = __reshi; let clo = getU128Parts(denominator); let chi = __reshi; let reslo = muldiv(alo, ahi, blo, bhi, clo, chi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Compute floor(sqrt(val)). * Supports positive values. * Traps if not I128Val (I128Object or I128SmallVal) value. * Traps if value is negative. To avoid, use "isNegative()". * @param val value * @returns result. */ export function i128sqrt(val:I128Val) : I128Val { if (isNegative(val) || isNegative(val)) { context.fail(); } let vlo = getI128Parts(val); let vhi = __reshi; let reslo = sqrt(vlo, vhi); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Compute floor(sqrt(val)). * Traps if not U128Val (U128Object or U128SmallVal) value. * @param val value * @returns result */ export function u128sqrt(val:U128Val) : U128Val { let vlo = getU128Parts(val); let vhi = __reshi; let reslo = sqrt(vlo, vhi); let reshi = __hi; return packU128Val(reshi, reslo); } /** * Calculate power of base with exponent. * Supports positive values. * Traps if not I128Val (I128Object or I128SmallVal) value. * Traps if value is negative. To avoid, use "isNegative()". * @param base base * @param exponent exponent * @returns result */ export function i128pow(base:I128Val, exponent:i32) : I128Val { if (isNegative(base)) { context.fail(); } let vlo = getI128Parts(base); let vhi = __reshi; let reslo = pow(vlo, vhi, exponent); let reshi = __hi; return packI128Val(reshi, reslo); } /** * Calculate power of base with exponent. * Traps if not U128Val (U128Object or U128SmallVal) value. * @param base base * @param exponent exponent * @returns result. */ export function u128pow(base:U128Val, exponent:i32) : U128Val { let vlo = getU128Parts(base); let vhi = __reshi; let reslo = pow(vlo, vhi, exponent); let reshi = __hi; return packU128Val(reshi, reslo); } /***************** HELPERS *****************/ // for internal usage only. var __reshi: u64 = 0; // returns lo part of the given i128 host val. Hi part is stored in __hi. // trasps if value does not represent an i128 host value (I128Object or I128SmallVal) function getI128Parts(value:I128Val) : u64 { let alo:u64 = 0; if (isI128Small(value)) { alo = toI128Small(value); __reshi = 0; } else if (isI128Object(value)) { alo = toI128Low64(value); __reshi = toI128High64(value); } else { context.fail(); } return alo; } // returns lo part of the given u128 host val. Hi part is stored in __hi. // trasps if value does not represent an u128 host value (U128Object or U128SmallVal) function getU128Parts(value:U128Val) : u64 { let alo:u64 = 0; if (isU128Small(value)) { alo = toU128Small(value); __reshi = 0; } else if (isU128Object(value)) { alo = toU128Low64(value); __reshi = toU128High64(value); } else { context.fail(); } return alo; } // converts a positive i128 into a raw host value. If it fits into 56 bits it returns I128SmallVal // otherwise it returns an I128Object. function packI128Val(vhi: u64, vlo: u64) : I128Val { if (vhi == 0 && vlo <= 0xFFFFFFFFFFFF) { // 56 bits return fromI128Small(vlo); } else { return fromI128Pieces(vhi, vlo); } } // converts a positive u128 into a raw host value. If it fits into 56 bits it returns U128SmallVal // otherwise it returns an U128Object. function packU128Val(vhi: u64, vlo: u64) : U128Val { if (vhi == 0 && vlo <= 0xFFFFFFFFFFFF) { // 56 bits return fromU128Small(vlo); } else { return fromU128Pieces(vhi, vlo); } }