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
   };


Reply via email to