Skip to content
Open
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
85 changes: 68 additions & 17 deletions include/constructors/constructors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "BigInt.hpp"
#include "functions/utility.hpp"
#include "operators/arithmetic_assignment.hpp"


/*
Expand Down Expand Up @@ -47,31 +48,81 @@ BigInt::BigInt(const long long& num) {
}


/*
Anonymous namespace
-----------------
Contains helper functions for constructing an BigInt from Strings
*/

namespace {

/*
parse_hex_string
--------------------
Parses the provided string store the result in magnitude.
str is assumed to have no sign. str must be in hex. First two chars are ignored
*/

void parse_hex_string(std::string &&str, std::string &magnitude) {
BigInt res;
for (size_t idx = 2; idx < str.size(); idx++) {
res *= 16;
char c = str[idx];
// digit
if (c >= '0' && c <= '9')
res += c - '0';
// lowercase hex
else if (c >= 'a' && c <= 'f')
res += c - 'a' + 10;
// uppercase hex
else if (c >= 'A' && c <= 'F')
res += c - 'A' + 10;
else
throw std::invalid_argument("Expected a hex integer, got \'" + str + "\'");
}
magnitude = res.to_string();
}


/*
parse_string
--------------------
Parses the provided string store the result in magnitude.
str is assumed to have no sign. str can be given in hex by prepending "0x"
*/

void parse_string(std::string &&str, std::string &magnitude) {
if (str.size() > 1 && str[0] == '0' && str[1] == 'x') {
parse_hex_string(std::move(str), magnitude);
return;
}

// check if every char is decimal
for (auto c : str)
if (c < '0' || c > '9')
throw std::invalid_argument("Expected a decimal integer, got \'" + str + "\'");

magnitude = std::move(str);
}

} // namespace

/*
String to BigInt
----------------
*/

BigInt::BigInt(const std::string& num) {
if (num[0] == '+' or num[0] == '-') { // check for sign
std::string magnitude = num.substr(1);
if (is_valid_number(magnitude)) {
value = magnitude;
std::string magnitude = num;
sign = '+';
if (magnitude[0] == '+' or magnitude[0] == '-') {
sign = num[0];
}
else {
throw std::invalid_argument("Expected an integer, got \'" + num + "\'");
}
}
else { // if no sign is specified
if (is_valid_number(num)) {
value = num;
sign = '+'; // positive by default
}
else {
throw std::invalid_argument("Expected an integer, got \'" + num + "\'");
}
// delete first char
magnitude.erase(0,1);
}

parse_string(std::move(magnitude), value);

strip_leading_zeroes(value);
}

Expand Down
15 changes: 0 additions & 15 deletions include/functions/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,6 @@
#include <tuple>


/*
is_valid_number
---------------
Checks whether the given string is a valid integer.
*/

bool is_valid_number(const std::string& num) {
for (char digit : num)
if (digit < '0' or digit > '9')
return false;

return true;
}


/*
strip_leading_zeroes
--------------------
Expand Down
31 changes: 29 additions & 2 deletions test/constructors/constructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ TEST_CASE("Construct zero-valued BigInts", "[constructors]") {
REQUIRE(num4 == 0);
}

TEST_CASE("Construct BigInts from hex strings", "[constructors]") {
BigInt num1_hex("0x0"); // should be 0 by default
BigInt num1_dec("0");
REQUIRE(num1_hex == 0);
REQUIRE(num1_hex == num1_dec);

BigInt num2("0xfa54"); // 0xf54 passed as an integer
REQUIRE(num2 == 0xfa54);

BigInt num3("0x0f7ab4d822924430b1b97859af0eaa41");
REQUIRE(num3 == "20575548111226062968771475379166554689");

BigInt num4("-0x0f7ab4d822924430b1b97859af0eaa41");
REQUIRE(num4 == "-20575548111226062968771475379166554689");

BigInt num5("-0x0F7AB4D822924430B1B97859AF0EAA41");
REQUIRE(num5 == "-20575548111226062968771475379166554689");
}

TEST_CASE("Randomly construct BigInts from integers and strings",
"[constructors][random][integer][string]") {
std::random_device generator;
Expand All @@ -39,13 +58,21 @@ TEST_CASE("Randomly construct BigInts from integers and strings",
BigInt trouble("123BigInt"); // without sign
}
catch (std::logic_error &e) {
CHECK(e.what() == std::string("Expected an integer, got \'123BigInt\'"));
CHECK(e.what() == std::string("Expected a decimal integer, got \'123BigInt\'"));
}
try {
BigInt trouble("-4a5b6c"); // with sign
// looks like hex, but is still not allowed
}
catch (std::logic_error &e) {
CHECK(e.what() == std::string("Expected an integer, got \'-4a5b6c\'"));
CHECK(e.what() == std::string("Expected a decimal integer, got \'4a5b6c\'"));
}

try {
BigInt trouble("0x4a5b6cg7923"); // with sign
// looks like hex, but contains illegal g
}
catch (std::logic_error &e) {
CHECK(e.what() == std::string("Expected a hex integer, got \'0x4a5b6cg7923\'"));
}
}