diff --git a/sources/BaseRealm/API/Math/BigInt.uc b/sources/BaseRealm/API/Math/BigInt.uc
index 66758d6..14bd402 100644
--- a/sources/BaseRealm/API/Math/BigInt.uc
+++ b/sources/BaseRealm/API/Math/BigInt.uc
@@ -1,7 +1,8 @@
/**
- * A simple big integer implementation, mostly to allow Acedia's databases to
- * store integers of arbitrary size.
- * Copyright 2022 Anton Tarasenko
+ * Author: dkanus
+ * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
+ * License: GPL
+ * Copyright 2022-2023 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
@@ -19,41 +20,22 @@
* along with Acedia. If not, see .
*/
class BigInt extends AcediaObject
- dependson(MathAPI);
-
-/**
- * # `BigInt`
- *
- * A simple big integer implementation, mostly to allow Acedia's databases to
- * store integers of arbitrary size. It can be used for long arithmetic
- * computations, but it was mainly meant as a players' statistics counter and,
- * therefore, not optimized for performing large amount of operations.
- *
- * ## Usage
- *
- * `BigInt` can be created from both `int` and decimal `BaseText`/`string`
- * representation, preferably by `MathAPI` (`_.math.`) methods
- * `ToBigInt()`/`MakeBigInt()`.
- * Then it can be combined either directly with other `BigInt` or with
- * `int`/`BaseText`/`string` through available arithmetic operations.
- * To make use of stored value one can convert it back into either `int` or
- * decimal `BaseText`/`string` representation.
- * Newly allocated `BigInt` is guaranteed to hold `0` as value.
- */
-
-/**
- * `BigInt` data as a `struct` - meant to be used to store `BigInt`'s values
- * inside the local databases.
- */
-struct BigIntData
-{
- var bool negative;
+ dependson(MathApi);
+
+/// A simple big integer implementation.
+///
+/// [`BigInt`]'s main purpose is to allow Acedia's databases to store integers of arbitrary size.
+/// It can be used for long arithmetic computations, but it was mainly meant as a players'
+/// statistics counter and, therefore, not optimized for performing large amount of operations.
+
+/// [`BigInt`] data as a struct - meant to be used to store [`BigInt`]'s values inside
+/// the local databases.
+struct BigIntData {
+ var bool negative;
var array digits;
};
-/**
- * Used to represent a result of comparison for `BigInt`s with each other.
- */
+/// Result of comparison for [`BigInt`]s with each other.
enum BigIntCompareResult
{
BICR_Less,
@@ -61,60 +43,60 @@ enum BigIntCompareResult
BICR_Greater
};
-// Does stored `BigInt` has negative sign?
+/// Does stored [`BigInt`] have a negative sign?
var private bool negative;
-// Digits array, from least to most significant. For example, for 13524:
-// `digits[0] = 4`
-// `digits[1] = 2`
-// `digits[2] = 5`
-// `digits[3] = 3`
-// `digits[4] = 1`
-// Valid `BigInt` should not have this array empty: zero should be
-// represented by an array with a single `0`-element.
-// This isn't a most efficient representation for `BigInt`, but it's easy
-// to convert to and from decimal representation.
-// INVARIANT: this array must not have leading (in the sense of significance)
-// zeroes. That is, last element of the array should not be a `0`. The only
-// exception if if stored value is `0`, then `digits` must consist of a single
-// `0` element.
+/// Digits array, from least to most significant. For example, for 13524:
+///
+/// ```
+/// `digits[0] = 4`
+/// `digits[1] = 2`
+/// `digits[2] = 5`
+/// `digits[3] = 3`
+/// `digits[4] = 1`
+/// ```
+///
+/// Valid [`BigInt`] should not have this array empty: zero should be represented by an array with
+/// a single `0`-element.
+/// This isn't a most efficient representation for [`BigInt`], but it's easy to convert to and from
+/// decimal representation.
+///
+/// # Invariants
+///
+/// This array must not have leading (in the sense of significance) zeroes.
+/// That is, last element of the array should not be a `0`.
+/// The only exception if if stored value is `0`, then `digits` must consist of
+/// a single `0` element.
var private array digits;
-// Constants useful for converting `BigInt` back to `int`, while avoiding
-// overflow.
-// We can add less digits than that without any fear of overflow
+/// Constants useful for converting [`BigInt`] back to [`int`], while avoiding overflow.
+/// We can add less digits than that without any fear of overflow.
const DIGITS_IN_MAX_INT = 10;
-// Maximum `int` value is `2147483647`, so in case most significant digit
-// is 10th and is `2` (so number has a form of "2xxxxxxxxx"), to check for
-// overflow we only need to compare combination of the rest of the digits with
-// this constant.
-const ALMOST_MAX_INT = 147483647;
-// To add last digit we add/subtract that digit multiplied by this value.
+/// Maximum [`int`] value is `2147483647`, so in case most significant digit is 10th and is `2`
+/// (so number has a form of `2xxxxxxxxx`), to check for overflow we only need to compare
+/// combination of the rest of the digits with this constant.
+const ALMOST_MAX_INT = 147483647;
+/// To add last digit we add/subtract that digit multiplied by this value.
const LAST_DIGIT_ORDER = 1000000000;
-protected function Constructor()
-{
+protected function Constructor() {
SetZero();
}
-protected function Finalizer()
-{
+protected function Finalizer() {
negative = false;
digits.length = 0;
}
// Auxiliary method to set current value to zero
-private function BigInt SetZero()
-{
+private function SetZero() {
negative = false;
digits.length = 1;
digits[0] = 0;
- return self;
}
-// Minimal `int` value `-2,147,483,648` is somewhat of a pain to handle, so
-// just use this auxiliary pre-made constructor for it
-private function BigInt SetMinimalNegative()
-{
+// Minimal [`int`] value `-2,147,483,648` is somewhat of a pain to handle, so just use this
+// auxiliary pre-made constructor for it
+private function SetMinimalNegative() {
negative = true;
digits.length = 10;
digits[0] = 8;
@@ -127,26 +109,23 @@ private function BigInt SetMinimalNegative()
digits[7] = 4;
digits[8] = 1;
digits[9] = 2;
- return self;
}
-// Removes unnecessary zeroes from leading digit positions `digits`.
-// Does not change contained value.
-private final function TrimLeadingZeroes()
-{
+// Removes unnecessary zeroes from leading digit positions `digits`.
+// Does not change contained value.
+private final function TrimLeadingZeroes() {
local int i, zeroesToRemove;
- // Find how many leading zeroes there is.
- // Since `digits` stores digits from least to most significant, we need
- // to check from the end of `digits` array.
- for (i = digits.length - 1; i >= 0; i -= 1)
- {
+ // Finds how many leading zeroes there is.
+ // Since `digits` stores digits from least to most significant, we need to check from the end of
+ // `digits` array.
+ for (i = digits.length - 1; i >= 0; i -= 1) {
if (digits[i] != 0) {
break;
}
zeroesToRemove += 1;
}
- // `digits` must not be empty, enforce `0` value in that case
+ // `digits` must not be empty, enforce `0` value in that case
if (zeroesToRemove >= digits.length) {
SetZero();
}
@@ -155,144 +134,125 @@ private final function TrimLeadingZeroes()
}
}
-/**
- * Changes current value of `BigInt` to given `BigInt` value.
- *
- * @param value New value of the caller `BigInt`. If `none` is given,
- * method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public final function BigInt Set(BigInt value)
+/// Changes current value of [`BigInt`] to given value.
+public final function Set(BigInt value)
{
- if (value == none) {
- return self;
+ if (value != none) {
+ value.TrimLeadingZeroes();
+ digits = value.digits;
+ negative = value.negative;
}
- value.TrimLeadingZeroes();
- digits = value.digits;
- negative = value.negative;
- return self;
}
-/**
- * Changes current value of `BigInt` to given `int` value `value`.
- *
- * Cannot fail.
- *
- * @param value New value of the caller `BigInt`.
- * @return Self-reference to allow for method chaining.
- */
-public final function BigInt SetInt(int value)
-{
- local MathAPI.IntegerDivisionResult divisionResult;
+/// Changes current value of [`BigInt`] to given value.
+public final function SetInt(int value) {
+ local MathApi.IntegerDivisionResult divisionResult;
negative = false;
digits.length = 0;
- if (value < 0)
- {
- // Treat special case of minimal `int` value `-2,147,483,648` that
- // won't fit into positive `int` as special and use pre-made
+ if (value < 0) {
+ // Treat special case of minimal [`int`] value `-2,147,483,648` that
+ // won't fit into positive [`int`] as special and use pre-made
// specialized constructor `CreateMinimalNegative()`
- if (value < -MaxInt) {
- return SetMinimalNegative();
- }
- else
- {
+ if (value < -maxInt) {
+ SetMinimalNegative();
+ return;
+ } else {
negative = true;
value *= -1;
}
}
if (value == 0) {
digits[0] = 0;
- }
- else
- {
- while (value > 0)
- {
+ } else {
+ while (value > 0) {
divisionResult = __().math.IntegerDivision(value, 10);
value = divisionResult.quotient;
digits[digits.length] = divisionResult.remainder;
}
}
TrimLeadingZeroes();
- return self;
}
-/**
- * Changes current value of `BigInt` to the value, given by decimal
- * representation inside `value` argument.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param value New value of the caller `BigInt`, given by decimal
- * its representation. If `none` is given, method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public final function BigInt SetDecimal(BaseText value)
-{
- local int i;
- local byte nextDigit;
- local Parser parser;
- local Basetext.Character nextCharacter;
+/// Changes current value of [`BigInt`] to the value, given by decimal representation.
+///
+/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given
+/// as an argument, caller's value won't change.
+/// Returns `true` in case of success and `false` otherwise.
+public final function bool SetDecimal(BaseText value) {
+ local int i;
+ local byte nextDigit;
+ local bool newNegative;
+ local array newDigits;
+ local Parser parser;
+ local Basetext.Character nextCharacter;
if (value == none) {
- return none;
+ return false;
}
parser = value.Parse();
- negative = parser.Match(P("-")).Ok();
- if (!parser.Ok()) {
- parser.R().Match(P("+")).Ok();
- }
- // Reset to valid state whether sign was consumed or not
+ newNegative = ParseSign(parser);
+ // Reset to valid state whether sign was consumed or not
parser.Confirm();
parser.R();
- // Reset current value
- digits.length = 0;
- digits.length = parser.GetRemainingLength();
- // Parse new one
- i = digits.length - 1;
- while (!parser.HasFinished())
- {
+ newDigits.length = parser.GetRemainingLength();
+ // Parse new one
+ i = newDigits.length - 1;
+ while (!parser.HasFinished()){
// This should not happen, but just in case
if (i < 0) {
break;
}
parser.MCharacter(nextCharacter);
- nextDigit = Clamp(__().text.CharacterToInt(nextCharacter), 0, 9);
- digits[i] = nextDigit;
+ nextDigit = __().text.CharacterToInt(nextCharacter, 10);
+ if (nextDigit < 0) {
+ return false;
+ }
+ newDigits[i] = nextDigit;
i -= 1;
}
parser.FreeSelf();
+ digits = newDigits;
+ negative = newNegative;
TrimLeadingZeroes();
- return self;
+ return true;
}
-/**
- * Changes current value of `BigInt` to the value, given by decimal
- * representation inside `value` argument.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param value New value of the caller `BigInt`, given by decimal
- * its representation.
- * @return Self-reference to allow for method chaining.
- */
-public final function BigInt SetDecimal_S(string value)
-{
+// Tries to parse either `+` or `-` and returns `true` iff it parsed `-`.
+// If neither got parsed, `parser` will enter failed state.
+// Assumes `parser` isn't `none`.
+private final function bool ParseSign(Parser parser) {
+ parser.Match(P("-"));
+ negative = parser.Ok();
+ if (parser.Ok()) {
+ negative = true;
+ }
+ else {
+ parser.R();
+ parser.Match(P("+"));
+ }
+ return negative;
+}
+
+/// Changes current value of [`BigInt`] to the value, given by decimal representation.
+///
+/// If invalid decimal representation (digits only, possibly with leading sign) is given as
+/// an argument, caller's value won't change.
+/// Returns `true` in case of success and `false` otherwise.
+public final function bool SetDecimal_S(string value) {
+ local bool result;
local MutableText wrapper;
wrapper = __().text.FromStringM(value);
- SetDecimal(wrapper);
+ result = SetDecimal(wrapper);
wrapper.FreeSelf();
- return self;
+ return result;
}
-// Auxiliary method for comparing two `BigInt`s by their absolute value.
-private function BigIntCompareResult _compareAbsolute(BigInt other)
-{
- local int i;
- local array otherDigits;
+// Auxiliary method for comparing two [`BigInt`]s by their absolute value.
+private function BigIntCompareResult _compareAbsolute(BigInt other) {
+ local int i;
+ local array otherDigits;
otherDigits = other.digits;
if (digits.length == otherDigits.length)
@@ -314,54 +274,34 @@ private function BigIntCompareResult _compareAbsolute(BigInt other)
return BICR_Greater;
}
-/**
- * Compares caller `BigInt` to `other`.
- *
- * @param other Value to compare the caller `BigInt`.
- * If given reference is `none` - behavior is undefined.
- * @return `BigIntCompareResult` representing the result of comparison.
- * Returned value describes how caller `BigInt` relates to the `other`,
- * e.g. if `BICR_Less` was returned - it means that caller `BigInt` is
- * smaller that `other`.
- */
-public function BigIntCompareResult Compare(BigInt other)
-{
+/// Compares caller [`BigInt`] to [`other`].
+///
+/// [`BigIntCompareResult`] representing the result of comparison is returned as a result.
+/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then
+/// it means that caller [`BigInt`] is smaller that `other`.
+/// If argument is `none`, then it is considered to be less ([`BICR_Less`]) than caller [`BigInt`].
+public function BigIntCompareResult Compare(BigInt other) {
local BigIntCompareResult resultForModulus;
- if (other == none) {
- return BICR_Less;
- }
- if (negative && !other.negative) {
- return BICR_Less;
- }
- if (!negative && other.negative) {
- return BICR_Greater;
- }
+ if (other == none) return BICR_Less;
+ if (negative && !other.negative) return BICR_Less;
+ if (!negative && other.negative) return BICR_Greater;
resultForModulus = _compareAbsolute(other);
- if (resultForModulus == BICR_Equal) {
- return BICR_Equal;
- }
- if ( (negative && (resultForModulus == BICR_Greater))
- || (!negative && (resultForModulus == BICR_Less)) )
- {
- return BICR_Less;
- }
+ if (resultForModulus == BICR_Equal) return BICR_Equal;
+ if (negative && (resultForModulus == BICR_Greater)) return BICR_Less;
+ if (!negative && (resultForModulus == BICR_Less)) return BICR_Less;
+
return BICR_Greater;
}
-/**
- * Compares caller `BigInt` to `other`.
- *
- * @param other Value to compare the caller `BigInt`.
- * @return `BigIntCompareResult` representing the result of comparison.
- * Returned value describes how caller `BigInt` relates to the `other`,
- * e.g. if `BICR_Less` was returned - it means that caller `BigInt` is
- * smaller that `other`.
- */
-public function BigIntCompareResult CompareInt(int other)
-{
- local BigInt wrapper;
- local BigIntCompareResult result;
+/// Compares caller [`BigInt`] to [`other`].
+///
+/// [`BigIntCompareResult`] representing the result of comparison is returned as a result.
+/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then
+/// it means that caller [`BigInt`] is smaller that `other`.
+public function BigIntCompareResult CompareInt(int other) {
+ local BigInt wrapper;
+ local BigIntCompareResult result;
wrapper = _.math.ToBigInt(other);
result = Compare(wrapper);
@@ -369,41 +309,33 @@ public function BigIntCompareResult CompareInt(int other)
return result;
}
-/**
- * Compares caller `BigInt` to `other`.
- *
- * @param other Value to compare the caller `BigInt`.
- * If given reference is `none` - behavior is undefined.
- * @return `BigIntCompareResult` representing the result of comparison.
- * Returned value describes how caller `BigInt` relates to the `other`,
- * e.g. if `BICR_Less` was returned - it means that caller `BigInt` is
- * smaller that `other`.
- */
-public function BigIntCompareResult CompareDecimal(BaseText other)
-{
- local BigInt wrapper;
- local BigIntCompareResult result;
+/// Compares caller [`BigInt`] to a decimal representation of a number.
+///
+/// [`BigIntCompareResult`] representing the result of comparison is returned as a result.
+/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then
+/// it means that caller [`BigInt`] is smaller that `other`.
+/// If argument is `none` or is an invalid decimal representation (digits only, possibly with
+/// leading sign, then it is considered to be less ([`BICR_Less`]) than caller [`BigInt`].
+public function BigIntCompareResult CompareDecimal(BaseText other) {
+ local BigInt wrapper;
+ local BigIntCompareResult result;
wrapper = _.math.MakeBigInt(other);
result = Compare(wrapper);
- wrapper.FreeSelf();
+ _.memory.Free(wrapper);
return result;
}
-/**
- * Compares caller `BigInt` to `other`.
- *
- * @param other Value to compare the caller `BigInt`.
- * If given value contains invalid decimal value - behavior is undefined.
- * @return `BigIntCompareResult` representing the result of comparison.
- * Returned value describes how caller `BigInt` relates to the `other`,
- * e.g. if `BICR_Less` was returned - it means that caller `BigInt` is
- * smaller that `other`.
- */
-public function BigIntCompareResult CompareDecimal_S(string other)
-{
- local BigInt wrapper;
- local BigIntCompareResult result;
+/// Compares caller [`BigInt`] to a decimal representation of a number.
+///
+/// [`BigIntCompareResult`] representing the result of comparison is returned as a result.
+/// It describes how caller [`BigInt`] relates to the `other`, e.g. if `BICR_Less` was returned then
+/// it means that caller [`BigInt`] is smaller that `other`.
+/// If argument is an invalid decimal representation (digits only, possibly with leading sign, then
+/// it is considered to be less ([`BICR_Less`]) than caller [`BigInt`].
+public function BigIntCompareResult CompareDecimal_S(string other) {
+ local BigInt wrapper;
+ local BigIntCompareResult result;
wrapper = _.math.MakeBigInt_S(other);
result = Compare(wrapper);
@@ -411,13 +343,11 @@ public function BigIntCompareResult CompareDecimal_S(string other)
return result;
}
-// Adds absolute values of caller `BigInt` and `other` with no changes to
-// the sign
-private function _add(BigInt other)
-{
- local int i;
- local byte carry, digitSum;
- local array otherDigits;
+// Adds absolute values of caller [`BigInt`] and [`other`] with no changes to the sign.
+private function _add(BigInt other) {
+ local int i;
+ local byte carry, digitSum;
+ local array otherDigits;
if (other == none) {
return;
@@ -425,13 +355,11 @@ private function _add(BigInt other)
otherDigits = other.digits;
if (digits.length < otherDigits.length) {
digits.length = otherDigits.length;
- }
- else {
+ } else {
otherDigits.length = digits.length;
}
carry = 0;
- for (i = 0; i < digits.length; i += 1)
- {
+ for (i = 0; i < digits.length; i += 1) {
digitSum = digits[i] + otherDigits[i] + carry;
digits[i] = _.math.Remainder(digitSum, 10);
carry = (digitSum - digits[i]) / 10;
@@ -442,47 +370,39 @@ private function _add(BigInt other)
// No leading zeroes can be created here, so no need to trim
}
-// Subtracts absolute value of `other` from the caller `BigInt`, flipping
-// caller's sign in case `other`'s absolute value is bigger.
-private function _sub(BigInt other)
-{
- local int i;
- local int carry, nextDigit;
- local array minuendDigits, subtrahendDigits;
- local BigIntCompareResult resultForModulus;
+// Subtracts absolute value of [`other`] from the caller [`BigInt`], flipping caller's sign in case
+// `other`'s absolute value is bigger.
+private function _sub(BigInt other) {
+ local int i;
+ local int carry, nextDigit;
+ local array minuendDigits, subtrahendDigits;
+ local BigIntCompareResult resultForModulus;
if (other == none) {
return;
}
resultForModulus = _compareAbsolute(other);
- if (resultForModulus == BICR_Equal)
- {
+ if (resultForModulus == BICR_Equal) {
SetZero();
return;
}
- if (resultForModulus == BICR_Less)
- {
- negative = !negative;
- minuendDigits = other.digits;
- subtrahendDigits = digits;
+ if (resultForModulus == BICR_Less) {
+ negative = !negative;
+ minuendDigits = other.digits;
+ subtrahendDigits = digits;
+ } else {
+ minuendDigits = digits;
+ subtrahendDigits = other.digits;
}
- else
- {
- minuendDigits = digits;
- subtrahendDigits = other.digits;
- }
- digits.length = minuendDigits.length;
+ digits.length = minuendDigits.length;
subtrahendDigits.length = minuendDigits.length;
carry = 0;
- for (i = 0; i < digits.length; i += 1)
- {
+ for (i = 0; i < digits.length; i += 1) {
nextDigit = int(minuendDigits[i]) - int(subtrahendDigits[i]) + carry;
- if (nextDigit < 0)
- {
+ if (nextDigit < 0) {
nextDigit += 10;
carry = -1;
- }
- else {
+ } else {
carry = 0;
}
digits[i] = nextDigit;
@@ -490,170 +410,108 @@ private function _sub(BigInt other)
TrimLeadingZeroes();
}
-/**
- * Adds `other` value to the caller `BigInt`.
- *
- * @param other Value to add. If `none` is given method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt Add(BigInt other)
-{
+/// Adds another value to the caller [`BigInt`].
+///
+/// If argument is `none`, then given method does nothing.
+public function Add(BigInt other) {
if (other == none) {
- return self;
+ return;
}
if (negative == other.negative) {
_add(other);
- }
- else {
+ } else {
_sub(other);
}
- return self;
}
-/**
- * Adds `other` value to the caller `BigInt`.
- *
- * Cannot fail.
- *
- * @param other Value to add.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt AddInt(int other)
-{
+/// Adds another value to the caller [`BigInt`].
+public function AddInt(int other) {
local BigInt otherObject;
otherObject = _.math.ToBigInt(other);
Add(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Adds `other` value to the caller `BigInt`.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param other Value to add. If `none` is given, method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt AddDecimal(BaseText other)
-{
+/// Adds decimal representation of the number to the caller [`BigInt`].
+///
+/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given -
+/// does nothing.
+public function AddDecimal(BaseText other) {
local BigInt otherObject;
if (other == none) {
- return self;
+ return;
}
otherObject = _.math.MakeBigInt(other);
Add(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Adds `other` value to the caller `BigInt`.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param other Value to add.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt AddDecimal_S(string other)
-{
+/// Adds decimal representation of the number to the caller [`BigInt`].
+///
+/// If invalid decimal representation (digits only, possibly with leading sign) is given -
+/// does nothing.
+public function AddDecimal_S(string other) {
local BigInt otherObject;
otherObject = _.math.MakeBigInt_S(other);
Add(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Subtracts `other` value to the caller `BigInt`.
- *
- * @param other Value to subtract. If `none` is given method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt Subtract(BigInt other)
-{
+/// Subtracts another value to the caller [`BigInt`].
+///
+/// If argument is `none`, then given method does nothing.
+public function Subtract(BigInt other) {
if (negative != other.negative) {
_add(other);
- }
- else {
+ } else {
_sub(other);
}
- return self;
}
-/**
- * Subtracts `other` value to the caller `BigInt`.
- *
- * Cannot fail.
- *
- * @param other Value to subtract.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt SubtractInt(int other)
-{
+/// Adds another value to the caller [`BigInt`].
+public function SubtractInt(int other) {
local BigInt otherObject;
otherObject = _.math.ToBigInt(other);
Subtract(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Subtracts `other` value to the caller `BigInt`.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param other Value to subtract. If `none`, method does nothing.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt SubtractDecimal(BaseText other)
-{
+/// Subtracts decimal representation of the number to the caller [`BigInt`].
+///
+/// If `none` or invalid decimal representation (digits only, possibly with leading sign) is given -
+/// does nothing.
+public function SubtractDecimal(BaseText other) {
local BigInt otherObject;
if (other == none) {
- return self;
+ return;
}
otherObject = _.math.MakeBigInt(other);
Subtract(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Subtracts `other` value to the caller `BigInt`.
- *
- * If invalid decimal representation (digits only, possibly with leading sign)
- * is given - behavior is undefined. Otherwise cannot fail.
- *
- * @param other Value to subtract.
- * @return Self-reference to allow for method chaining.
- */
-public function BigInt SubtractDecimal_S(string other)
-{
+/// Adds decimal representation of the number to the caller [`BigInt`].
+///
+/// If invalid decimal representation (digits only, possibly with leading sign) is given -
+/// does nothing.
+public function SubtractDecimal_S(string other) {
local BigInt otherObject;
otherObject = _.math.MakeBigInt_S(other);
Subtract(otherObject);
_.memory.Free(otherObject);
- return self;
}
-/**
- * Checks if caller `BigInt` is negative. Zero is not considered negative
- * number.
- *
- * @return `true` if stored value is negative (`< 0`) and `false` otherwise
- * (`>= 0`).
- */
-public function bool IsNegative()
-{
+/// Checks if caller [`BigInt`] is negative.
+///
+/// Returns if stored value is negative and `false` otherwise.
+/// Zero is not considered negative number.
+public function bool IsNegative() {
// Handle special case of zero first (it ignores `negative` flag)
if (digits.length == 1 && digits[0] == 0) {
return false;
@@ -661,19 +519,12 @@ public function bool IsNegative()
return negative;
}
-/**
- * Converts caller `BigInt` into `int` representation.
- *
- * In case stored value is outside `int`'s value range
- * (`[-MaxInt-1, MaxInt] == [-2147483648; 2147483647]`),
- * method returns either maximal or minimal possible value, depending on
- * the `BigInt`'s sign.
- *
- * @return `int` representation of the caller `BigInt`, clamped into available
- * `int` value range.
- */
-public function int ToInt()
-{
+/// Converts caller [`BigInt`] into [`int`] representation.
+///
+/// In case stored value is outside `int`'s value range
+/// (`[-maxInt-1, maxInt] == [-2147483648; 2147483647]`), method returns either maximal or minimal
+// possible value, depending on the [`BigInt`]'s sign.
+public function int ToInt() {
local int i;
local int accumulator;
local int safeDigitsAmount;
@@ -681,19 +532,16 @@ public function int ToInt()
if (digits.length <= 0) {
return 0;
}
- if (digits.length > DIGITS_IN_MAX_INT)
- {
+ if (digits.length > DIGITS_IN_MAX_INT) {
if (negative) {
- return (-MaxInt - 1);
- }
- else {
- return MaxInt;
+ return (-maxInt - 1);
+ } else {
+ return maxInt;
}
}
- // At most `DIGITS_IN_MAX_INT - 1` iterations
+ // At most `DIGITS_IN_MAX_INT - 1` iterations
safeDigitsAmount = Min(DIGITS_IN_MAX_INT - 1, digits.length);
- for (i = safeDigitsAmount - 1; i >= 0; i -= 1)
- {
+ for (i = safeDigitsAmount - 1; i >= 0; i -= 1) {
accumulator *= 10;
accumulator += digits[i];
}
@@ -704,33 +552,28 @@ public function int ToInt()
return accumulator;
}
-// Adding `DIGITS_IN_MAX_INT - 1` will never lead to an overflow, but
-// adding the next digit can, so we need to handle it differently and more
-// carefully.
-// Assumes `digits.length <= DIGITS_IN_MAX_INT`.
-private function int AddUnsafeDigitToInt(int accumulator)
-{
- local int unsafeDigit;
- local bool noOverflow;
+/// Adding `DIGITS_IN_MAX_INT - 1` will never lead to an overflow, but adding the next digit can,
+/// so we need to handle it differently and more carefully.
+/// Assumes `digits.length <= DIGITS_IN_MAX_INT`.
+private function int AddUnsafeDigitToInt(int accumulator) {
+ local int unsafeDigit;
+ local bool noOverflow;
if (digits.length < DIGITS_IN_MAX_INT) {
return accumulator;
}
unsafeDigit = digits[DIGITS_IN_MAX_INT - 1];
- // `MaxInt` stats with `2`, so if last/unsafe digit is either `0` or `1`,
- // there is no overflow, otherwise - check rest of the digits
+ // `maxInt` stats with `2`, so if last/unsafe digit is either `0` or `1`, there is no overflow,
+ // otherwise - check rest of the digits
noOverflow = (unsafeDigit < 2);
- if (unsafeDigit == 2)
- {
- // Include `MaxInt` and `-MaxInt-1` (minimal possible value) into
- // an overflow too - this way we still give a correct result, but do
- // not have to worry about `int`-arithmetic error
+ if (unsafeDigit == 2) {
+ // Include `maxInt` and `-maxInt-1` (minimal possible value) into an overflow too - this way
+ // we still give a correct result, but do not have to worry about `int`-arithmetic error
noOverflow = noOverflow
|| (negative && (accumulator > -ALMOST_MAX_INT - 1))
|| (!negative && (accumulator < ALMOST_MAX_INT));
}
- if (noOverflow)
- {
+ if (noOverflow) {
if (negative) {
accumulator -= unsafeDigit * LAST_DIGIT_ORDER;
}
@@ -741,30 +584,20 @@ private function int AddUnsafeDigitToInt(int accumulator)
}
// Handle overflow
if (negative) {
- return (-MaxInt - 1);
+ return (-maxInt - 1);
}
- return MaxInt;
+ return maxInt;
}
-/**
- * Converts caller `BigInt` into `Text` representation.
- *
- * @return `Text` representation of the caller `BigInt`.
- */
-public function Text ToText()
-{
+/// Converts caller [`BigInt`] into [`Text`] representation.
+public function Text ToText() {
return ToText_M().IntoText();
}
-/**
- * Converts caller `BigInt` into `MutableText` representation.
- *
- * @return `MutableText` representation of the caller `BigInt`.
- */
-public function MutableText ToText_M()
-{
- local int i;
- local MutableText result;
+/// Converts caller [`BigInt`] into [`MutableText`] representation.
+public function MutableText ToText_M() {
+ local int i;
+ local MutableText result;
result = _.text.Empty();
if (negative) {
@@ -776,15 +609,10 @@ public function MutableText ToText_M()
return result;
}
-/**
- * Converts caller `BigInt` into `string` representation.
- *
- * @return `string` representation of the caller `BigInt`.
- */
-public function string ToString()
-{
- local int i;
- local string result;
+/// Converts caller [`BigInt`] into [`string`] representation.
+public function string ToString() {
+ local int i;
+ local string result;
if (negative) {
result = "-";
@@ -795,20 +623,14 @@ public function string ToString()
return result;
}
-/**
- * Restores `BigInt` from the `BigIntData` value.
- *
- * This method is created to make an efficient way to store `BigInt` inside
- * local databases.
- *
- * @param data Data to read new caller `BigInt`'s value from.
- */
-public function FromData(BigIntData data)
-{
+/// Restores [`BigInt`] from the [`BigIntData`] value.
+///
+/// This method is created to make an efficient way to store [`BigInt`].
+public function FromData(BigIntData data) {
local int i;
- negative = data.negative;
- digits = data.digits;
+ negative = data.negative;
+ digits = data.digits;
// Deal with possibly erroneous data
for (i = 0; i < digits.length; i += 1) {
if (digits[i] > 9) {
@@ -817,23 +639,16 @@ public function FromData(BigIntData data)
}
}
-/**
- * Converts caller `BigInt`'s value into `BigIntData`.
- *
- * This method is created to make an efficient way to store `BigInt` inside
- * local databases.
- *
- * @return Value of the caller `BigInt` in the `struct` form.
- */
-public function BigIntData ToData()
-{
+/// Converts caller [`BigInt`]'s value into [`BigIntData`].
+///
+/// This method is created to make an efficient way to store [`BigInt`].
+public function BigIntData ToData() {
local BigIntData result;
result.negative = negative;
- result.digits = digits;
+ result.digits = digits;
return result;
}
-defaultproperties
-{
+defaultproperties {
}
\ No newline at end of file
diff --git a/sources/BaseRealm/API/Math/MathAPI.uc b/sources/BaseRealm/API/Math/MathAPI.uc
index 504f546..1f4f8da 100644
--- a/sources/BaseRealm/API/Math/MathAPI.uc
+++ b/sources/BaseRealm/API/Math/MathAPI.uc
@@ -37,36 +37,41 @@ public function BigInt ToBigInt(int value)
local BigInt result;
result = BigInt(_.memory.Allocate(class'BigInt'));
- return result.SetInt(value);
+ result.SetInt(value);
+ return result;
}
/// Creates new `BigInt` value, based on the decimal number representation.
///
-/// Expects valid decimal representation as input (digits only, possibly with leading sign),
-/// otherwise contents of returned value are undefined.
-/// If invalid decimal representation is given - contents of returned value are undefined.
-/// Otherwise cannot fail and is guaranteed to return non-`none` value.
+/// If (and only if) `none` or invalid decimal representation (digits only, possibly with
+/// leading sign) is given as an argument, method will return `none`.
public function BigInt MakeBigInt(BaseText value)
{
local BigInt result;
result = BigInt(_.memory.Allocate(class'BigInt'));
- return result.SetDecimal(value);
+ if (result.SetDecimal(value)) {
+ return result;
+ }
+ result.FreeSelf();
+ return none;
}
/// Creates new `BigInt` value, based on the decimal number representation.
///
-/// Expects valid decimal representation as input (digits only, possibly with leading sign),
-/// otherwise contents of returned value are undefined.
-/// If invalid decimal representation is given - contents of returned value are undefined.
-/// Otherwise cannot fail and is guaranteed to return non-`none` value.
+/// If (and only if) invalid decimal representation (digits only, possibly with leading sign) is
+/// given as an argument, method will return `none`.
public function BigInt MakeBigInt_S(string value)
{
local BigInt result;
result = BigInt(_.memory.Allocate(class'BigInt'));
- return result.SetDecimal_S(value);
+ if (result.SetDecimal_S(value)) {
+ return result;
+ }
+ result.FreeSelf();
+ return none;
}
/// Computes remainder of the integer division of [`number`] by [`divisor`].
@@ -79,7 +84,7 @@ public function int Remainder(int number, int divisor)
local int quotient;
quotient = number / divisor;
- return (number - quotient/// divisor);
+ return (number - quotient * divisor);
}
/// Computes quotient and remainder of the integer division of [`number`] by [`divisor`].
diff --git a/sources/BaseRealm/API/Math/Tests/TEST_BigInt.uc b/sources/BaseRealm/API/Math/Tests/TEST_BigInt.uc
index c90785c..d327b26 100644
--- a/sources/BaseRealm/API/Math/Tests/TEST_BigInt.uc
+++ b/sources/BaseRealm/API/Math/Tests/TEST_BigInt.uc
@@ -1,6 +1,8 @@
/**
- * Set of tests for `BigInt` class.
- * Copyright 2022 Anton Tarasenko
+ * Author: dkanus
+ * Home repo: https://www.insultplayers.ru/git/AcediaFramework/AcediaCore
+ * License: GPL
+ * Copyright 2022-2023 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
@@ -20,8 +22,7 @@
class TEST_BigInt extends TestCase
abstract;
-protected static function TESTS()
-{
+protected static function TESTS() {
// Here we use `ToString()` method to check `BigInt` creation,
// therefore also testing it
Context("Testing creation of `BigInt`s.");
@@ -36,43 +37,33 @@ protected static function TESTS()
Test_SubtractingValues();
}
-protected static function Test_Creating()
-{
+protected static function Test_Creating() {
Issue("`ToString()` doesn't return value `BigInt` was initialized with" @
"a positive `int`.");
TEST_ExpectTrue(__().math.ToBigInt(13524).ToString() == "13524");
- TEST_ExpectTrue(
- __().math.ToBigInt(MaxInt).ToString() == "2147483647");
+ TEST_ExpectTrue(__().math.ToBigInt(MaxInt).ToString() == "2147483647");
Issue("`ToString()` doesn't return value `BigInt` was initialized with" @
"a positive integer inside `string`.");
- TEST_ExpectTrue(
- __().math.MakeBigInt_S("2147483647").ToString()
- == "2147483647");
+ TEST_ExpectTrue(__().math.MakeBigInt_S("2147483647").ToString() == "2147483647");
TEST_ExpectTrue(
__().math.MakeBigInt_S("4238756872643464981264982128742389")
.ToString() == "4238756872643464981264982128742389");
- Issue("`ToString()` doesn't return value `BigInt` was initialized with" @
- "a negative `int`.");
+ Issue("`ToString()` doesn't return value `BigInt` was initialized with a negative `int`.");
TEST_ExpectTrue(__().math.ToBigInt(-666).ToString() == "-666");
- TEST_ExpectTrue(
- __().math.ToBigInt(-MaxInt).ToString() == "-2147483647");
- TEST_ExpectTrue(
- __().math.ToBigInt(-MaxInt - 1).ToString() == "-2147483648");
+ TEST_ExpectTrue(__().math.ToBigInt(-MaxInt).ToString() == "-2147483647");
+ TEST_ExpectTrue(__().math.ToBigInt(-MaxInt - 1).ToString() == "-2147483648");
Issue("`ToString()` doesn't return value `BigInt` was initialized with" @
"a negative integer inside `string`.");
- TEST_ExpectTrue(
- __().math.MakeBigInt_S("-2147483648").ToString()
- == "-2147483648");
+ TEST_ExpectTrue(__().math.MakeBigInt_S("-2147483648").ToString() == "-2147483648");
TEST_ExpectTrue(
__().math.MakeBigInt_S("-238473846327894632879097410348127")
.ToString() == "-238473846327894632879097410348127");
}
-protected static function Test_ToText()
-{
+protected static function Test_ToText() {
Issue("`ToText()` doesn't return value `BigInt` was initialized with" @
"a positive integer inside `string`.");
TEST_ExpectTrue(__().math
@@ -96,20 +87,19 @@ protected static function Test_ToText()
.ToString() == "-9827657892365923510176386357863078603212901078175829");
}
-protected static function Test_AddingValues()
-{
+protected static function Test_AddingValues() {
SubTest_AddingSameSignValues();
SubTest_AddingDifferentSignValues();
}
-protected static function SubTest_AddingSameSignValues()
-{
+protected static function SubTest_AddingSameSignValues() {
local BigInt main, addition;
Issue("Two positive `BigInt`s are incorrectly added.");
main = __().math.MakeBigInt_S("927641962323462271784269213864");
addition = __().math.MakeBigInt_S("16324234842947239847239239");
main.Add(addition);
+ Log("UMBRA" @ main.ToString());
TEST_ExpectTrue(main.ToString() == "927658286558305219024116453103");
main = __().math.MakeBigInt_S("16324234842947239847239239");
addition = __().math.MakeBigInt_S("927641962323462271784269213864");
@@ -135,8 +125,7 @@ protected static function SubTest_AddingSameSignValues()
TEST_ExpectTrue(main.ToString() == "-1457931745873178552");
}
-protected static function SubTest_AddingDifferentSignValues()
-{
+protected static function SubTest_AddingDifferentSignValues() {
local BigInt main, addition;
Issue("Negative `BigInt`s is incorrectly added to positive one.");
@@ -168,14 +157,12 @@ protected static function SubTest_AddingDifferentSignValues()
TEST_ExpectTrue(main.ToString() == "0");
}
-protected static function Test_SubtractingValues()
-{
+protected static function Test_SubtractingValues() {
SubTest_SubtractingSameSignValues();
SubTest_SubtractingDifferentSignValues();
}
-protected static function SubTest_SubtractingSameSignValues()
-{
+protected static function SubTest_SubtractingSameSignValues() {
local BigInt main, sub;
Issue("Two positive `BigInt`s are incorrectly subtracted.");
@@ -207,8 +194,7 @@ protected static function SubTest_SubtractingSameSignValues()
TEST_ExpectTrue(main.ToString() == "0");
}
-protected static function SubTest_SubtractingDifferentSignValues()
-{
+protected static function SubTest_SubtractingDifferentSignValues() {
local BigInt main, sub;
Issue("Negative `BigInt`s is incorrectly subtracted from positive one.");
@@ -240,8 +226,7 @@ protected static function SubTest_SubtractingDifferentSignValues()
TEST_ExpectTrue(main.ToString() == "-1457931745873178552");
}
-protected static function Test_ToInt()
-{
+protected static function Test_ToInt() {
Issue("Testing conversion for non-overflowing values.");
TEST_ExpectTrue(__().math.MakeBigInt_S("0").ToInt() == 0);
TEST_ExpectTrue(__().math.MakeBigInt_S("-0").ToInt() == 0);
@@ -264,8 +249,7 @@ protected static function Test_ToInt()
__().math.MakeBigInt_S("-32545657348437563873").ToInt() == -2147483648);
}
-defaultproperties
-{
- caseGroup = "Math"
- caseName = "BigInt"
+defaultproperties {
+ caseGroup = "Math"
+ caseName = "BigInt"
}
\ No newline at end of file