aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-06-23 16:29:29 +0200
committerDavid Robillard <d@drobilla.net>2020-10-27 13:13:58 +0100
commit992c8bce3e1938609193561028d67b86753e6e5b (patch)
tree7743e3ae4260eb37ec02202e6bd578d412126c8e
parent6f2d3942dff7e176f4771ea6134ffcc88e33ef42 (diff)
downloadserd-992c8bce3e1938609193561028d67b86753e6e5b.tar.gz
serd-992c8bce3e1938609193561028d67b86753e6e5b.tar.bz2
serd-992c8bce3e1938609193561028d67b86753e6e5b.zip
Add faster decimal digit counting function
-rw-r--r--src/decimal.c25
-rw-r--r--src/decimal.h26
-rw-r--r--src/node.c3
-rw-r--r--tests/decimal_test.c55
-rw-r--r--wscript4
5 files changed, 112 insertions, 1 deletions
diff --git a/src/decimal.c b/src/decimal.c
new file mode 100644
index 00000000..7f78c8a7
--- /dev/null
+++ b/src/decimal.c
@@ -0,0 +1,25 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "decimal.h"
+
+#include "int_math.h"
+
+int
+serd_count_digits(const uint64_t i)
+{
+ return i == 0 ? 1 : (int)serd_ilog10(i) + 1;
+}
diff --git a/src/decimal.h b/src/decimal.h
new file mode 100644
index 00000000..11e6a9bf
--- /dev/null
+++ b/src/decimal.h
@@ -0,0 +1,26 @@
+/*
+ Copyright 2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_DECIMAL_H
+#define SERD_DECIMAL_H
+
+#include <stdint.h>
+
+/// Return the number of decimal digits required to represent `n`
+int
+serd_count_digits(uint64_t i);
+
+#endif // SERD_DECIMAL_H
diff --git a/src/node.c b/src/node.c
index 633f4567..b362aaa8 100644
--- a/src/node.c
+++ b/src/node.c
@@ -16,6 +16,7 @@
#include "node.h"
+#include "decimal.h"
#include "namespaces.h"
#include "static_nodes.h"
#include "string_utils.h"
@@ -640,7 +641,7 @@ serd_new_integer(int64_t i, const SerdNode* datatype)
{
const SerdNode* type = datatype ? datatype : &serd_xsd_integer.node;
uint64_t abs_i = (uint64_t)((i < 0) ? -i : i);
- const unsigned digits = serd_digits((double)abs_i);
+ const unsigned digits = (unsigned)serd_count_digits(abs_i);
const size_t type_len = serd_node_total_size(type);
const size_t total_len = digits + 2 + type_len;
diff --git a/tests/decimal_test.c b/tests/decimal_test.c
new file mode 100644
index 00000000..b0361e2c
--- /dev/null
+++ b/tests/decimal_test.c
@@ -0,0 +1,55 @@
+/*
+ Copyright 2011-2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#undef NDEBUG
+
+#include "../src/decimal.h"
+
+#include <assert.h>
+
+static void
+test_count_digits(void)
+{
+ assert(1 == serd_count_digits(0));
+ assert(1 == serd_count_digits(1));
+ assert(1 == serd_count_digits(9));
+ assert(2 == serd_count_digits(10));
+ assert(2 == serd_count_digits(99ull));
+ assert(3 == serd_count_digits(999ull));
+ assert(4 == serd_count_digits(9999ull));
+ assert(5 == serd_count_digits(99999ull));
+ assert(6 == serd_count_digits(999999ull));
+ assert(7 == serd_count_digits(9999999ull));
+ assert(8 == serd_count_digits(99999999ull));
+ assert(9 == serd_count_digits(999999999ull));
+ assert(10 == serd_count_digits(9999999999ull));
+ assert(11 == serd_count_digits(99999999999ull));
+ assert(12 == serd_count_digits(999999999999ull));
+ assert(13 == serd_count_digits(9999999999999ull));
+ assert(14 == serd_count_digits(99999999999999ull));
+ assert(15 == serd_count_digits(999999999999999ull));
+ assert(16 == serd_count_digits(9999999999999999ull));
+ assert(17 == serd_count_digits(99999999999999999ull));
+ assert(18 == serd_count_digits(999999999999999999ull));
+ assert(19 == serd_count_digits(9999999999999999999ull));
+ assert(20 == serd_count_digits(18446744073709551615ull));
+}
+
+int
+main(void)
+{
+ test_count_digits();
+}
diff --git a/wscript b/wscript
index 585789d6..b43626d0 100644
--- a/wscript
+++ b/wscript
@@ -73,6 +73,7 @@ def configure(conf):
'msvc': [
'/wd4061', # enumerator in switch is not explicitly handled
'/wd4200', # nonstandard: zero-sized array in struct/union
+ '/wd4464', # relative include path contains '..'
'/wd4514', # unreferenced inline function has been removed
'/wd4710', # function not inlined
'/wd4711', # function selected for automatic inline expansion
@@ -168,6 +169,7 @@ lib_source = ['src/base64.c',
'src/byte_sink.c',
'src/byte_source.c',
'src/cursor.c',
+ 'src/decimal.c',
'src/env.c',
'src/inserter.c',
'src/int_math.c',
@@ -255,6 +257,7 @@ def build(bld):
for prog in [('serdi_static', 'src/serdi.c'),
('base64_test', 'tests/base64_test.c'),
('cursor_test', 'tests/cursor_test.c'),
+ ('decimal_test', 'tests/decimal_test.c'),
('env_test', 'tests/env_test.c'),
('free_null_test', 'tests/free_null_test.c'),
('int_math_test', 'tests/int_math_test.c'),
@@ -686,6 +689,7 @@ def test(tst):
with tst.group('Unit') as check:
check(['./base64_test'])
check(['./cursor_test'])
+ check(['./decimal_test'])
check(['./env_test'])
check(['./free_null_test'])
check(['./int_math_test'])