diff options
author | Sven Gothel <[email protected]> | 2022-09-03 04:32:27 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-09-03 04:32:27 +0200 |
commit | ba7716cb60bad10b892f834e1b1175d81926565f (patch) | |
tree | 7b1cdc6643de4016a20e7248d5327d93af7f71f7 | |
parent | 2f1b1f1599566ca9f50d89ce540325a233458aad (diff) |
variable radix conversion: Overload for int64_t `dec_to_radix()`, validate base, enhance tests
-rw-r--r-- | include/jau/string_util.hpp | 5 | ||||
-rw-r--r-- | java_base/org/jau/util/BasicTypes.java | 53 | ||||
-rw-r--r-- | src/basic_types.cpp | 28 | ||||
-rw-r--r-- | test/java/jau/test/util/TestBasicTypes.java | 57 | ||||
-rw-r--r-- | test/test_basictypeconv.cpp | 41 |
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]" ) { |