Abstracted BaseX_2_10 to work with arbitrary containers and digit-types
This commit is contained in:
parent
e1cf366e25
commit
1903f19b96
@ -3,36 +3,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace {
|
|
||||||
// Fast 64-bit int power function
|
|
||||||
inline std::uint64_t Powuli(const std::uint64_t &b, const std::uint64_t &e) {
|
|
||||||
std::uint64_t buf = 1;
|
|
||||||
|
|
||||||
for (std::uint64_t i = 0; i < e; i++)
|
|
||||||
buf *= b;
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint64_t GeneralUtility::BaseX_2_10(const std::string& num, const std::string& set) {
|
|
||||||
// If base is 0, throw logic error
|
|
||||||
if (set.length() == 0)
|
|
||||||
throw std::logic_error("Can't convert from base0! Please supply a nonempty set!");
|
|
||||||
|
|
||||||
unsigned long long int buf = 0;
|
|
||||||
for (std::size_t i = 0; i < num.length(); i++) {
|
|
||||||
for (std::size_t j = 0; j < set.length(); j++) {
|
|
||||||
if (num[i] == set[j]) {
|
|
||||||
buf += Powuli((std::uint64_t)set.length(), (uint64_t)(num.length() - (i + 1))) * j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Based on: https://www.geeksforgeeks.org/divide-large-number-represented-string/
|
// Based on: https://www.geeksforgeeks.org/divide-large-number-represented-string/
|
||||||
std::pair<std::string, int>
|
std::pair<std::string, int>
|
||||||
GeneralUtility::StringDivision(const std::string& dividend, const unsigned int divisor, const std::string& set) {
|
GeneralUtility::StringDivision(const std::string& dividend, const unsigned int divisor, const std::string& set) {
|
||||||
|
@ -27,7 +27,8 @@ public:
|
|||||||
//! \param num A string representing the number
|
//! \param num A string representing the number
|
||||||
//! \param set The set/base of the number
|
//! \param set The set/base of the number
|
||||||
//! \return A 64-bit integer representing the number
|
//! \return A 64-bit integer representing the number
|
||||||
static std::uint64_t BaseX_2_10(const std::string& num, const std::string& set);
|
template <class T_Container>
|
||||||
|
static std::uint64_t BaseX_2_10(const T_Container& num, const T_Container& set);
|
||||||
|
|
||||||
//! Will convert a number to an arbitrary base.
|
//! Will convert a number to an arbitrary base.
|
||||||
//! This just a wrapper for BaseX_2_Y.
|
//! This just a wrapper for BaseX_2_Y.
|
||||||
@ -49,6 +50,37 @@ private:
|
|||||||
GeneralUtility();
|
GeneralUtility();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Fast 64-bit int power function
|
||||||
|
inline std::uint64_t Powuli(const std::uint64_t &b, const std::uint64_t &e) {
|
||||||
|
std::uint64_t buf = 1;
|
||||||
|
|
||||||
|
for (std::uint64_t i = 0; i < e; i++)
|
||||||
|
buf *= b;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T_Container>
|
||||||
|
std::uint64_t GeneralUtility::BaseX_2_10(const T_Container& num, const T_Container& set) {
|
||||||
|
// If base is 0, throw logic error
|
||||||
|
if (set.size() == 0)
|
||||||
|
throw std::logic_error("Can't convert from base0! Please supply a nonempty set!");
|
||||||
|
|
||||||
|
unsigned long long int buf = 0;
|
||||||
|
for (std::size_t i = 0; i < num.size(); i++) {
|
||||||
|
for (std::size_t j = 0; j < set.size(); j++) {
|
||||||
|
if (num[i] == set[j]) {
|
||||||
|
buf += Powuli((std::uint64_t)set.size(), (uint64_t)(num.size() - (i + 1))) * j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T_Type, class T_Container>
|
template<typename T_Type, class T_Container>
|
||||||
int GeneralUtility::Ord(const T_Type& item, const T_Container& set) {
|
int GeneralUtility::Ord(const T_Type& item, const T_Container& set) {
|
||||||
const auto result =
|
const auto result =
|
||||||
|
@ -65,6 +65,26 @@ TEST_CASE(__FILE__"/BaseFuckingBig_to_10", "[BaseX_2_10]")
|
|||||||
TEST_CASE(__FILE__"/NoSetSupplied", "[BaseX_2_10]")
|
TEST_CASE(__FILE__"/NoSetSupplied", "[BaseX_2_10]")
|
||||||
{
|
{
|
||||||
REQUIRE_THROWS_AS(
|
REQUIRE_THROWS_AS(
|
||||||
GeneralUtility::BaseX_2_10("699", "")
|
GeneralUtility::BaseX_2_10<std::string>("699", "")
|
||||||
, std::logic_error);
|
, std::logic_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that conversion with more complex 'digits' works. Weird-ass usecase
|
||||||
|
TEST_CASE(__FILE__"/BaseWeird_to_10", "[BaseX_2_10]")
|
||||||
|
{
|
||||||
|
// Setup
|
||||||
|
|
||||||
|
// Yes... That is actually our base...
|
||||||
|
const std::vector<std::string> set = { "Banana", "Apple", "Peach", "Strawberry", "Tomato", "Cherry" };
|
||||||
|
|
||||||
|
// Yes, that is a fucking number. It's 69 in whatever the fuck that base is
|
||||||
|
const std::vector<std::string> in = { "Apple", "Cherry", "Strawberry" };
|
||||||
|
|
||||||
|
const std::uint64_t expected_out = 69;
|
||||||
|
|
||||||
|
// Exercise
|
||||||
|
const std::uint64_t out = GeneralUtility::BaseX_2_10(in, set);
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
REQUIRE(out == expected_out);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user