Author: stefan2
Date: Fri Apr 13 18:27:38 2012
New Revision: 1325896
URL: http://svn.apache.org/viewvc?rev=1325896&view=rev
Log:
Provide functions for efficient int64 -> ASCII conversion.
They have been designed for usage in serialization code
(e.g. svn://)
* subversion/include/private/svn_string_private.h
(SVN_INT64_BUFFER_SIZE): new constant
(svn__ui64toa, svn__i64toa): declare new private API
* subversion/libsvn_subr/svn_string.c
(decimal_table): new lookup table
(COPY_TWO_BYTES): new platform abstraction macro
(svn__ui64toa, svn__i64toa): implement new API
* subversion/tests/libsvn_subr/string-test.c
(test24): new test for new API
Modified:
subversion/trunk/subversion/include/private/svn_string_private.h
subversion/trunk/subversion/libsvn_subr/svn_string.c
subversion/trunk/subversion/tests/libsvn_subr/string-test.c
Modified: subversion/trunk/subversion/include/private/svn_string_private.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_string_private.h?rev=1325896&r1=1325895&r2=1325896&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_string_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_string_private.h Fri Apr 13
18:27:38 2012
@@ -58,6 +58,26 @@ svn_stringbuf__morph_into_string(svn_str
* with APR 0.9 */
apr_status_t
svn__strtoff(apr_off_t *offset, const char *buf, char **end, int base);
+
+/** Number of chars needed to represent signed (19 places + sign + NUL) or
+ * unsigned (20 places + NUL) integers as strings.
+ */
+#define SVN_INT64_BUFFER_SIZE 21
+
+/** Writes the @a number as string into @a dest. The latter must provide
+ * space for at least #SVN_INT64_BUFFER_SIZE characters. Returns the number
+ * chars written excluding the terminating NUL.
+ */
+apr_size_t
+svn__ui64toa(char * dest, apr_uint64_t number);
+
+/** Writes the @a number as string into @a dest. The latter must provide
+ * space for at least #SVN_INT64_BUFFER_SIZE characters. Returns the number
+ * chars written excluding the terminating NUL.
+ */
+apr_size_t
+svn__i64toa(char * dest, apr_int64_t number);
+
/** @} */
/** @} */
Modified: subversion/trunk/subversion/libsvn_subr/svn_string.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/svn_string.c?rev=1325896&r1=1325895&r2=1325896&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/svn_string.c (original)
+++ subversion/trunk/subversion/libsvn_subr/svn_string.c Fri Apr 13 18:27:38
2012
@@ -920,3 +920,108 @@ svn__strtoff(apr_off_t *offset, const ch
return apr_strtoff(offset, buf, end, base);
#endif
}
+
+/* "Precalculated" itoa values for 2 places (including leading zeros).
+ * For maximum performance, make sure all table entries are word-aligned.
+ */
+static const char decimal_table[100][4]
+ = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09"
+ , "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"
+ , "20", "21", "22", "23", "24", "25", "26", "27", "28", "29"
+ , "30", "31", "32", "33", "34", "35", "36", "37", "38", "39"
+ , "40", "41", "42", "43", "44", "45", "46", "47", "48", "49"
+ , "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"
+ , "60", "61", "62", "63", "64", "65", "66", "67", "68", "69"
+ , "70", "71", "72", "73", "74", "75", "76", "77", "78", "79"
+ , "80", "81", "82", "83", "84", "85", "86", "87", "88", "89"
+ , "90", "91", "92", "93", "94", "95", "96", "97", "98", "99"};
+
+/* Copy the two bytes at SOURCE[0] and SOURCE[1] to DEST[0] and DEST[1] */
+#if SVN_UNALIGNED_ACCESS_IS_OK
+#define COPY_TWO_BYTES(dest,source)\
+ *(apr_uint16_t*)(dest) = *(apr_uint16_t*)(source);
+#else
+#define COPY_TWO_BYTES(dest,source) \
+ dest[0] = source[0]; \
+ dest[1] = source[1];
+#endif
+
+apr_size_t
+svn__ui64toa(char * dest, apr_uint64_t number)
+{
+ char buffer[SVN_INT64_BUFFER_SIZE];
+ apr_uint32_t reduced; /* used for 32 bit DIV */
+ char* target;
+
+ /* Small numbers are by far the most common case.
+ * Therefore, we use special code.
+ */
+ if (number < 100)
+ {
+ if (number < 10)
+ {
+ dest[0] = (char)('0' + number);
+ dest[1] = 0;
+ return 1;
+ }
+ else
+ {
+ COPY_TWO_BYTES(dest, decimal_table[(apr_size_t)number]);
+ dest[2] = 0;
+ return 2;
+ }
+ }
+
+ /* Standard code. Write string in pairs of chars back-to-front */
+ buffer[SVN_INT64_BUFFER_SIZE - 1] = 0;
+ target = &buffer[SVN_INT64_BUFFER_SIZE - 3];
+
+ /* Loop may be executed 0 .. 2 times. */
+ while (number >= 100000000)
+ {
+ /* Number is larger than 100^4, i.e. we can write 4x2 chars.
+ * Also, use 32 bit DIVs as these are about twice as fast.
+ */
+ reduced = number % 100000000;
+ number /= 100000000;
+
+ COPY_TWO_BYTES(target - 0, decimal_table[reduced % 100]);
+ reduced /= 100;
+ COPY_TWO_BYTES(target - 2, decimal_table[reduced % 100]);
+ reduced /= 100;
+ COPY_TWO_BYTES(target - 4, decimal_table[reduced % 100]);
+ reduced /= 100;
+ COPY_TWO_BYTES(target - 6, decimal_table[reduced % 100]);
+ target -= 8;
+ }
+
+ /* Now, the number fits into 32 bits, but is larger than 1 */
+ reduced = (apr_uint32_t)(number);
+ while (reduced >= 100)
+ {
+ COPY_TWO_BYTES(target, decimal_table[reduced % 100]);
+ reduced /= 100;
+ target -= 2;
+ }
+
+ /* The number is now smaller than 100 but larger than 1 */
+ COPY_TWO_BYTES(target, decimal_table[reduced]);
+
+ /* Correction for uneven count of places. */
+ if (reduced < 10)
+ ++target;
+
+ /* Copy to target */
+ memcpy(dest, target, &buffer[SVN_INT64_BUFFER_SIZE] - target);
+ return &buffer[SVN_INT64_BUFFER_SIZE] - target - 1;
+}
+
+apr_size_t
+svn__i64toa(char * dest, apr_int64_t number)
+{
+ if (number >= 0)
+ return svn__ui64toa(dest, (apr_uint64_t)number);
+
+ *dest = '-';
+ return svn__ui64toa(dest + 1, (apr_uint64_t)(0-number)) + 1;
+}
\ No newline at end of file
Modified: subversion/trunk/subversion/tests/libsvn_subr/string-test.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/string-test.c?rev=1325896&r1=1325895&r2=1325896&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/string-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/string-test.c Fri Apr 13
18:27:38 2012
@@ -39,7 +39,7 @@
#include "svn_io.h"
#include "svn_error.h"
#include "svn_string.h" /* This includes <apr_*.h> */
-
+#include "private/svn_string_private.h"
/* A quick way to create error messages. */
static svn_error_t *
@@ -511,6 +511,35 @@ test23(apr_pool_t *pool)
return test_stringbuf_unequal("abc", "abb", pool);
}
+static svn_error_t *
+test24(apr_pool_t *pool)
+{
+ char buffer[SVN_INT64_BUFFER_SIZE];
+ apr_size_t length;
+
+ length = svn__i64toa(buffer, 0);
+ SVN_TEST_ASSERT(length == 1);
+ SVN_TEST_STRING_ASSERT(buffer, "0");
+
+ length = svn__i64toa(buffer, -0x8000000000000000ll);
+ SVN_TEST_ASSERT(length == 20);
+ SVN_TEST_STRING_ASSERT(buffer, "-9223372036854775808");
+
+ length = svn__i64toa(buffer, 0x7fffffffffffffffll);
+ SVN_TEST_ASSERT(length == 19);
+ SVN_TEST_STRING_ASSERT(buffer, "9223372036854775807");
+
+ length = svn__ui64toa(buffer, 0);
+ SVN_TEST_ASSERT(length == 1);
+ SVN_TEST_STRING_ASSERT(buffer, "0");
+
+ length = svn__ui64toa(buffer, 0xffffffffffffffffll);
+ SVN_TEST_ASSERT(length == 20);
+ SVN_TEST_STRING_ASSERT(buffer, "18446744073709551615");
+
+ return test_stringbuf_unequal("abc", "abb", pool);
+}
+
/*
====================================================================
If you add a new test to this file, update this array.
@@ -568,5 +597,7 @@ struct svn_test_descriptor_t test_funcs[
"compare stringbufs; different lengths"),
SVN_TEST_PASS2(test23,
"compare stringbufs; same length, different content"),
+ SVN_TEST_PASS2(test24,
+ "verify i64toa"),
SVN_TEST_NULL
};