aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-09-03 04:32:27 +0200
committerSven Gothel <[email protected]>2022-09-03 04:32:27 +0200
commitba7716cb60bad10b892f834e1b1175d81926565f (patch)
tree7b1cdc6643de4016a20e7248d5327d93af7f71f7
parent2f1b1f1599566ca9f50d89ce540325a233458aad (diff)
variable radix conversion: Overload for int64_t `dec_to_radix()`, validate base, enhance tests
-rw-r--r--include/jau/string_util.hpp5
-rw-r--r--java_base/org/jau/util/BasicTypes.java53
-rw-r--r--src/basic_types.cpp28
-rw-r--r--test/java/jau/test/util/TestBasicTypes.java57
-rw-r--r--test/test_basictypeconv.cpp41
5 files changed, 162 insertions, 22 deletions
diff --git a/include/jau/string_util.hpp b/include/jau/string_util.hpp
index c03c691..9c9c0e0 100644
--- a/include/jau/string_util.hpp
+++ b/include/jau/string_util.hpp
@@ -226,7 +226,8 @@ namespace jau {
* @return the encoded radix string or an empty string if base > 82 or num is negative
* @see radix_to_dec()
*/
- std::string dec_to_radix(int num, const int base, const int padding_width=0, const char padding_char='0') noexcept;
+ std::string dec_to_radix(int32_t num, const int32_t base, const unsigned int padding_width=0, const char padding_char='0') noexcept;
+ std::string dec_to_radix(int64_t num, const int32_t base, const unsigned int padding_width=0, const char padding_char='0') noexcept;
/**
* Converts a given positive decimal number to a symbolic string using given radix.
@@ -238,7 +239,7 @@ namespace jau {
* @return the decoded radix decimal value or -1 if base > 82
* @see dec_to_radix()
*/
- int radix_to_dec(const std::string_view& str, const int base) noexcept;
+ int64_t radix_to_dec(const std::string_view& str, const int base) noexcept;
/**
// *************************************************
diff --git a/java_base/org/jau/util/BasicTypes.java b/java_base/org/jau/util/BasicTypes.java
index 34d101f..1868e08 100644
--- a/java_base/org/jau/util/BasicTypes.java
+++ b/java_base/org/jau/util/BasicTypes.java
@@ -231,10 +231,11 @@ public class BasicTypes {
* @param padding_width minimal width of the encoded radix string
* @param padding_char padding character, usually '0'
* @return the encoded radix string or an empty string if base > 143 or num is negative
+ * @see #dec_to_radix(long, int, int, char)
* @see #radix_to_dec(String, int)
*/
public static String dec_to_radix(int num, final int base, final int padding_width, final char padding_char) {
- if( 0 > num || base > radix_max_base ) {
+ if( 0 > num || 0 >= base || base > radix_max_base ) {
return "";
}
@@ -257,6 +258,37 @@ public class BasicTypes {
*
* @param num a positive decimal number
* @param base radix to use, either 62, 82 or 143 where 143 is the maximum.
+ * @param padding_width minimal width of the encoded radix string
+ * @param padding_char padding character, usually '0'
+ * @return the encoded radix string or an empty string if base > 143 or num is negative
+ * @see #dec_to_radix(int, int, int, char)
+ * @see #radix_to_dec(String, int)
+ */
+ public static String dec_to_radix(long num, final int base, final int padding_width, final char padding_char) {
+ if( 0 > num || 0 >= base || base > radix_max_base ) {
+ return "";
+ }
+
+ final StringBuilder res = new StringBuilder();
+ final long lbase = base;
+ do {
+ res.insert( 0, radix_symbols.charAt( (int)( num % lbase ) ) );
+ num /= lbase;
+ } while ( 0 != num );
+
+ for(int i=res.length(); i<padding_width; ++i) {
+ res.insert(0, padding_char);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Converts a given positive decimal number to a symbolix string using given radix.
+ *
+ * See {@link #dec_to_radix(int, int, int)} for details.
+ *
+ * @param num a positive decimal number
+ * @param base radix to use, either 62, 82 or 143 where 143 is the maximum.
* @return the encoded radix string or an empty string if base > 143 or num is negative
* @see #dec_to_radix(int, int, int, char)
* @see #radix_to_dec(String, int)
@@ -266,6 +298,21 @@ public class BasicTypes {
}
/**
+ * Converts a given positive decimal number to a symbolix string using given radix.
+ *
+ * See {@link #dec_to_radix(int, int, int)} for details.
+ *
+ * @param num a positive decimal number
+ * @param base radix to use, either 62, 82 or 143 where 143 is the maximum.
+ * @return the encoded radix string or an empty string if base > 143 or num is negative
+ * @see #dec_to_radix(long, int, int, char)
+ * @see #radix_to_dec(String, int)
+ */
+ public static String dec_to_radix(final long num, final int base) {
+ return dec_to_radix(num, base, 0 /* padding_width */, '0');
+ }
+
+ /**
* Converts a given positive decimal number to a symbolic string using given radix.
*
* See {@link #dec_to_radix(int, int, int)} for details.
@@ -275,12 +322,12 @@ public class BasicTypes {
* @return the decoded radix decimal value or -1 if base > 143
* @see #dec_to_radix(int, int)
*/
- public static int radix_to_dec(final String str, final int base) {
+ public static long radix_to_dec(final String str, final int base) {
if( base > radix_max_base ) {
return -1;
}
final int str_len = str.length();
- int res = 0;
+ long res = 0;
for (int i = 0; i < str_len; ++i) {
res = res * base + radix_symbols.indexOf(str.charAt(i));
}
diff --git a/src/basic_types.cpp b/src/basic_types.cpp
index a6f7033..88640d8 100644
--- a/src/basic_types.cpp
+++ b/src/basic_types.cpp
@@ -423,9 +423,9 @@ std::string& jau::byteHexString(std::string& dest, const uint8_t value, const bo
static constexpr const int radix_max_base = 82;
static const std::string radix_symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#%&()+,-.;=@[]^_{}~";
-std::string jau::dec_to_radix(int num, const int base, const int padding_width, const char padding_char) noexcept
+std::string jau::dec_to_radix(int32_t num, const int32_t base, const unsigned int padding_width, const char padding_char) noexcept
{
- if( 0 > num || base > radix_max_base ) {
+ if( 0 > num || 0 >= base || base > radix_max_base ) {
return "";
}
std::string res;
@@ -435,18 +435,36 @@ std::string jau::dec_to_radix(int num, const int base, const int padding_width,
num = quotient.quot;
} while ( 0 != num );
- for(int i=res.length(); i<padding_width; ++i) {
+ for(unsigned int i=res.length(); i<padding_width; ++i) {
res.insert(res.begin(), padding_char);
}
return res;
}
-int jau::radix_to_dec(const std::string_view& str, const int base) noexcept
+std::string jau::dec_to_radix(int64_t num, const int32_t base, const unsigned int padding_width, const char padding_char) noexcept
+{
+ if( 0 > num || 0 >= base || base > radix_max_base ) {
+ return "";
+ }
+ std::string res;
+ do {
+ std::lldiv_t quotient = std::lldiv(num, (int64_t)base);
+ res.insert( res.begin(), radix_symbols[ quotient.rem ] );
+ num = quotient.quot;
+ } while ( 0 != num );
+
+ for(unsigned int i=res.length(); i<padding_width; ++i) {
+ res.insert(res.begin(), padding_char);
+ }
+ return res;
+}
+
+int64_t jau::radix_to_dec(const std::string_view& str, const int base) noexcept
{
if( base > radix_max_base ) {
return -1;
}
- int res = 0;
+ int64_t res = 0;
for (std::string::size_type pos = 0; pos < str.length(); ++pos) {
res = res * base + radix_symbols.find(str[pos]);
}
diff --git a/test/java/jau/test/util/TestBasicTypes.java b/test/java/jau/test/util/TestBasicTypes.java
index 79b728f..0f4e7dd 100644
--- a/test/java/jau/test/util/TestBasicTypes.java
+++ b/test/java/jau/test/util/TestBasicTypes.java
@@ -60,12 +60,12 @@ public class TestBasicTypes {
}
- private static void testRadix(final int base) {
+ private static void testRadix32(final int base) {
final String r1_max = BasicTypes.dec_to_radix(base-1, base, 3, '0');
final String r1_max_s = BasicTypes.dec_to_radix(base-1, base);
final String r3_max = r1_max_s.concat(r1_max_s).concat(r1_max_s);
- final int min = BasicTypes.radix_to_dec("0", base);
- final int max = BasicTypes.radix_to_dec(r3_max, base);
+ final int min = (int)BasicTypes.radix_to_dec("0", base);
+ final int max = (int)BasicTypes.radix_to_dec(r3_max, base);
System.err.printf("Test base %d: [%d .. %d] <-> ['%s' .. '%s'], %d years (max/365d) \n",
base, min, max, BasicTypes.dec_to_radix(min, base), BasicTypes.dec_to_radix(max, base), (max/365));
@@ -79,35 +79,74 @@ public class TestBasicTypes {
Assert.assertEquals("1", BasicTypes.dec_to_radix(1, base));
Assert.assertEquals("001", BasicTypes.dec_to_radix(1, base, 3, '0'));
{
- final int v0_d = BasicTypes.radix_to_dec(r1_max, base);
+ final int v0_d = (int)BasicTypes.radix_to_dec(r1_max, base);
final String v1_s = BasicTypes.dec_to_radix(base-1, base, 3, '0');
Assert.assertEquals(r1_max, v1_s);
Assert.assertEquals(base-1, v0_d);
}
{
- final int v0_d = BasicTypes.radix_to_dec(r3_max, base);
+ final int v0_d = (int)BasicTypes.radix_to_dec(r3_max, base);
final String v1_s = BasicTypes.dec_to_radix(max, base, 3, '0');
Assert.assertEquals(r3_max, v1_s);
Assert.assertEquals(max, v0_d);
}
for(int iter=min; iter<=max; ++iter) {
final String rad = BasicTypes.dec_to_radix(iter, base, 3, '0');
- final int dec = BasicTypes.radix_to_dec(rad, base);
+ final int dec = (int)BasicTypes.radix_to_dec(rad, base);
+ Assert.assertEquals(iter, dec);
+ }
+ }
+
+ private static void testRadix64(final int base, final long min, final long max) {
+ final int padding = 9;
+ final String r1_max = BasicTypes.dec_to_radix(base-1, base, padding, '0');
+
+ System.err.printf("Test base %d: [%d .. %d] <-> ['%s' .. '%s'], %d years (max/365d) \n",
+ base, min, max, BasicTypes.dec_to_radix(min, base), BasicTypes.dec_to_radix(max, base), (max/365));
+
+ Assert.assertEquals(0, BasicTypes.radix_to_dec("000", base));
+ Assert.assertEquals("0", BasicTypes.dec_to_radix(0, base));
+
+ Assert.assertEquals(1, BasicTypes.radix_to_dec("001", base));
+ Assert.assertEquals("1", BasicTypes.dec_to_radix(1, base));
+ {
+ final long v0_d = BasicTypes.radix_to_dec(r1_max, base);
+ final String v1_s = BasicTypes.dec_to_radix(base-1, base, padding, '0');
+ Assert.assertEquals(r1_max, v1_s);
+ Assert.assertEquals(base-1, v0_d);
+ }
+ for(long iter=Math.max(0L, min-1); iter<max; ) {
+ ++iter;
+ final String rad = BasicTypes.dec_to_radix(iter, base, padding, '0');
+ final long dec = BasicTypes.radix_to_dec(rad, base);
+ if( false ) {
+ System.err.printf("test base %d: iter %d, rad '%s', dec %d\n", base, iter, rad, dec);
+ }
Assert.assertEquals(iter, dec);
}
}
@Test
public void test01RadixBase62() {
- testRadix(62);
+ testRadix32(62);
+ testRadix64(62, 0x7fffff00L, 0x80000100L);
+ testRadix64(62, 0xFFFFFFF0L, 0x100000010L);
+ testRadix64(62, 0x7FFFFFFFFFFFFFF0L, 0x7FFFFFFFFFFFFFFFL);
+
}
@Test
public void test02RadixBase82() {
- testRadix(82);
+ testRadix32(82);
+ testRadix64(82, 0x7fffff00L, 0x80000100L);
+ testRadix64(82, 0xFFFFFFF0L, 0x100000010L);
+ testRadix64(82, 0x7FFFFFFFFFFFFFF0L, 0x7FFFFFFFFFFFFFFFL);
}
@Test
public void test03RadixBase143() {
- testRadix(143);
+ testRadix32(143);
+ testRadix64(143, 0x7fffff00L, 0x80000100L);
+ testRadix64(143, 0xFFFFFFF0L, 0x100000010L);
+ testRadix64(143, 0x7FFFFFFFFFFFFFF0L, 0x7FFFFFFFFFFFFFFFL);
}
public static void main(final String args[]) {
diff --git a/test/test_basictypeconv.cpp b/test/test_basictypeconv.cpp
index 4978b7c..1dab771 100644
--- a/test/test_basictypeconv.cpp
+++ b/test/test_basictypeconv.cpp
@@ -388,7 +388,7 @@ TEST_CASE( "Integer Type Test Test 05", "[integer][type]" ) {
REQUIRE( 3_unz == (jau::nsize_t)3 );
}
-static void testRadix(const int base) {
+static void testRadix32(const int base) {
{
// UTF-8 (or codepage 437) <-> ASCII collision
const std::string s1 = "Ç";
@@ -444,12 +444,47 @@ static void testRadix(const int base) {
}
}
+static void testRadix64(const int base, const int64_t min, const int64_t max) {
+ const int padding = 9;
+ const std::string r1_max = jau::dec_to_radix(base-1, base, padding, '0');
+
+ fprintf(stderr, "Test base %d: [%" PRIi64 " .. %" PRIi64 "] <-> ['%s' .. '%s'], %" PRIi64 " years (max/365d) \n",
+ base, min, max, jau::dec_to_radix(min, base).c_str(), jau::dec_to_radix(max, base).c_str(), (max/365));
+
+ REQUIRE(0 == jau::radix_to_dec("000", base));
+ REQUIRE("0" == jau::dec_to_radix(0, base));
+
+ REQUIRE(1 == jau::radix_to_dec("001", base));
+ REQUIRE("1" == jau::dec_to_radix(1, base));
+ {
+ const int64_t v0_d = jau::radix_to_dec(r1_max, base);
+ const std::string v1_s = jau::dec_to_radix(base-1, base, padding, '0');
+ REQUIRE(r1_max == v1_s);
+ REQUIRE(base-1 == v0_d);
+ }
+ for(int64_t iter=std::max(0_i64, min-1); iter<max; ) {
+ ++iter;
+ const std::string rad = jau::dec_to_radix(iter, base, padding, '0');
+ const int64_t dec = jau::radix_to_dec(rad, base);
+#if 0
+ fprintf(stderr, "test base %d: iter %" PRIi64 ", rad '%s', dec %" PRIi64 "\n", base, iter, rad.c_str(), dec);
+#endif
+ REQUIRE(iter == dec);
+ }
+}
+
TEST_CASE( "Radix Base 62 Test 05", "[integer][type]" ) {
- testRadix(62);
+ testRadix32(62);
+ testRadix64(62, 0x7fffff00, 0x80000100_i64);
+ testRadix64(62, 0xFFFFFFF0_i64, 0x100000010_i64);
+ testRadix64(62, 0x7FFFFFFFFFFFFFF0_i64, 0x7FFFFFFFFFFFFFFF_i64);
}
TEST_CASE( "Radix Base 82 Test 05", "[integer][type]" ) {
- testRadix(82);
+ testRadix32(82);
+ testRadix64(82, 0x7fffff00, 0x80000100_i64);
+ testRadix64(82, 0xFFFFFFF0_i64, 0x100000010_i64);
+ testRadix64(82, 0x7FFFFFFFFFFFFFF0_i64, 0x7FFFFFFFFFFFFFFF_i64);
}
// TEST_CASE( "Radix Base 143 Test 05", "[integer][type]" ) {