fast_excel 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -7
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -1
  5. data/examples/example.rb +2 -0
  6. data/examples/example_date_time.rb +38 -0
  7. data/fast_excel.gemspec +2 -2
  8. data/lib/fast_excel/binding/format.rb +17 -0
  9. data/lib/fast_excel/binding/workbook.rb +39 -17
  10. data/lib/fast_excel/binding/worksheet.rb +57 -13
  11. data/lib/fast_excel/binding.rb +7 -7
  12. data/lib/fast_excel.rb +27 -20
  13. data/libxlsxwriter/.github/FUNDING.yml +1 -0
  14. data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
  15. data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
  16. data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
  17. data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
  18. data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
  19. data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
  20. data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
  21. data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
  22. data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
  23. data/libxlsxwriter/.gitignore +16 -1
  24. data/libxlsxwriter/.indent.pro +24 -0
  25. data/libxlsxwriter/CMakeLists.txt +156 -56
  26. data/libxlsxwriter/CONTRIBUTING.md +2 -2
  27. data/libxlsxwriter/Changes.txt +344 -2
  28. data/libxlsxwriter/LICENSE.txt +66 -8
  29. data/libxlsxwriter/Makefile +151 -54
  30. data/libxlsxwriter/Package.swift +42 -0
  31. data/libxlsxwriter/Readme.md +4 -2
  32. data/libxlsxwriter/build.zig +324 -0
  33. data/libxlsxwriter/build.zig.zon +11 -0
  34. data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
  35. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
  36. data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
  37. data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
  38. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
  39. data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  40. data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
  41. data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
  42. data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  43. data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  44. data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
  45. data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
  46. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  47. data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
  48. data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
  49. data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  50. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  51. data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
  52. data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
  53. data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  54. data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
  55. data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
  56. data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
  57. data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
  58. data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
  59. data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  60. data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
  61. data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
  62. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
  63. data/libxlsxwriter/include/xlsxwriter.h +4 -2
  64. data/libxlsxwriter/libxlsxwriter.podspec +8 -5
  65. data/libxlsxwriter/src/Makefile +58 -21
  66. data/libxlsxwriter/src/app.c +5 -2
  67. data/libxlsxwriter/src/chart.c +396 -81
  68. data/libxlsxwriter/src/chartsheet.c +22 -22
  69. data/libxlsxwriter/src/comment.c +443 -0
  70. data/libxlsxwriter/src/content_types.c +40 -1
  71. data/libxlsxwriter/src/core.c +2 -2
  72. data/libxlsxwriter/src/custom.c +1 -1
  73. data/libxlsxwriter/src/drawing.c +160 -40
  74. data/libxlsxwriter/src/format.c +109 -25
  75. data/libxlsxwriter/src/hash_table.c +1 -1
  76. data/libxlsxwriter/src/metadata.c +283 -0
  77. data/libxlsxwriter/src/packager.c +794 -94
  78. data/libxlsxwriter/src/relationships.c +1 -1
  79. data/libxlsxwriter/src/shared_strings.c +2 -4
  80. data/libxlsxwriter/src/styles.c +353 -58
  81. data/libxlsxwriter/src/table.c +304 -0
  82. data/libxlsxwriter/src/theme.c +1 -1
  83. data/libxlsxwriter/src/utility.c +143 -43
  84. data/libxlsxwriter/src/vml.c +1062 -0
  85. data/libxlsxwriter/src/workbook.c +567 -77
  86. data/libxlsxwriter/src/worksheet.c +6668 -1462
  87. data/libxlsxwriter/src/xmlwriter.c +95 -5
  88. data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
  89. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
  90. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
  91. data/libxlsxwriter/third_party/md5/Makefile +42 -0
  92. data/libxlsxwriter/third_party/md5/md5.c +291 -0
  93. data/libxlsxwriter/third_party/md5/md5.h +45 -0
  94. data/libxlsxwriter/third_party/minizip/Makefile +3 -8
  95. data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
  96. data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
  97. data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
  98. data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
  99. data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
  100. data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
  101. data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
  102. data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
  103. data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
  104. data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
  105. data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
  106. data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
  107. data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
  108. data/libxlsxwriter/third_party/minizip/zip.c +165 -218
  109. data/libxlsxwriter/third_party/minizip/zip.h +164 -154
  110. data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
  111. data/libxlsxwriter/version.txt +1 -1
  112. data/test/auto_width_test.rb +20 -0
  113. data/test/default_format_test.rb +1 -1
  114. data/test/validations_test.rb +3 -3
  115. data/test/worksheet_test.rb +6 -1
  116. metadata +33 -7
  117. data/libxlsxwriter/.travis.yml +0 -37
@@ -3,19 +3,21 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
10
10
  #include <stdio.h>
11
11
  #include <string.h>
12
12
  #include <stdlib.h>
13
+ #include <ctype.h>
13
14
  #include "xlsxwriter/xmlwriter.h"
14
15
 
15
16
  #define LXW_AMP "&amp;"
16
17
  #define LXW_LT "&lt;"
17
18
  #define LXW_GT "&gt;"
18
19
  #define LXW_QUOT "&quot;"
20
+ #define LXW_NL "&#xA;"
19
21
 
20
22
  /* Defines. */
21
23
  #define LXW_MAX_ENCODED_ATTRIBUTE_LENGTH (LXW_MAX_ATTRIBUTE_LENGTH*6)
@@ -177,6 +179,10 @@ _escape_attributes(struct xml_attribute *attribute)
177
179
  memcpy(p_encoded, LXW_QUOT, sizeof(LXW_QUOT) - 1);
178
180
  p_encoded += sizeof(LXW_QUOT) - 1;
179
181
  break;
182
+ case '\n':
183
+ memcpy(p_encoded, LXW_NL, sizeof(LXW_NL) - 1);
184
+ p_encoded += sizeof(LXW_NL) - 1;
185
+ break;
180
186
  default:
181
187
  *p_encoded = *p_attr;
182
188
  p_encoded++;
@@ -227,7 +233,24 @@ lxw_escape_data(const char *data)
227
233
  }
228
234
 
229
235
  /*
230
- * Escape control characters in strings with with _xHHHH_.
236
+ * Check for control characters in strings.
237
+ */
238
+ uint8_t
239
+ lxw_has_control_characters(const char *string)
240
+ {
241
+ while (string) {
242
+ /* 0xE0 == 0b11100000 masks values > 0x19 == 0b00011111. */
243
+ if (!(*string & 0xE0) && *string != 0x0A && *string != 0x09)
244
+ return LXW_TRUE;
245
+
246
+ string++;
247
+ }
248
+
249
+ return LXW_FALSE;
250
+ }
251
+
252
+ /*
253
+ * Escape control characters in strings with _xHHHH_.
231
254
  */
232
255
  char *
233
256
  lxw_escape_control_characters(const char *string)
@@ -283,6 +306,67 @@ lxw_escape_control_characters(const char *string)
283
306
  return encoded;
284
307
  }
285
308
 
309
+ /*
310
+ * Escape special characters in URL strings with with %XX.
311
+ */
312
+ char *
313
+ lxw_escape_url_characters(const char *string, uint8_t escape_hash)
314
+ {
315
+
316
+ size_t escape_len = sizeof("%XX") - 1;
317
+ size_t encoded_len = (strlen(string) * escape_len + 1);
318
+
319
+ char *encoded = (char *) calloc(encoded_len, 1);
320
+ char *p_encoded = encoded;
321
+
322
+ while (*string) {
323
+ switch (*string) {
324
+ case ' ':
325
+ case '"':
326
+ case '<':
327
+ case '>':
328
+ case '[':
329
+ case ']':
330
+ case '`':
331
+ case '^':
332
+ case '{':
333
+ case '}':
334
+ lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
335
+ p_encoded += escape_len;
336
+ break;
337
+ case '#':
338
+ /* This is only escaped for "external:" style links. */
339
+ if (escape_hash) {
340
+ lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
341
+ p_encoded += escape_len;
342
+ }
343
+ else {
344
+ *p_encoded = *string;
345
+ p_encoded++;
346
+ }
347
+ break;
348
+ case '%':
349
+ /* Only escape % if it isn't already an escape. */
350
+ if (!isxdigit(*(string + 1)) || !isxdigit(*(string + 2))) {
351
+ lxw_snprintf(p_encoded, escape_len + 1, "%%%2x", *string);
352
+ p_encoded += escape_len;
353
+ }
354
+ else {
355
+ *p_encoded = *string;
356
+ p_encoded++;
357
+ }
358
+ break;
359
+ default:
360
+ *p_encoded = *string;
361
+ p_encoded++;
362
+ break;
363
+ }
364
+ string++;
365
+ }
366
+
367
+ return encoded;
368
+ }
369
+
286
370
  /* Write out escaped attributes. */
287
371
  STATIC void
288
372
  _fprint_escaped_attributes(FILE * xmlfile,
@@ -294,7 +378,7 @@ _fprint_escaped_attributes(FILE * xmlfile,
294
378
  STAILQ_FOREACH(attribute, attributes, list_entries) {
295
379
  fprintf(xmlfile, " %s=", attribute->key);
296
380
 
297
- if (!strpbrk(attribute->value, "&<>\"")) {
381
+ if (!strpbrk(attribute->value, "&<>\"\n")) {
298
382
  fprintf(xmlfile, "\"%s\"", attribute->value);
299
383
  }
300
384
  else {
@@ -341,12 +425,18 @@ lxw_new_attribute_str(const char *key, const char *value)
341
425
 
342
426
  /* Create a new integer XML attribute. */
343
427
  struct xml_attribute *
344
- lxw_new_attribute_int(const char *key, uint32_t value)
428
+ lxw_new_attribute_int(const char *key, uint64_t value)
345
429
  {
346
430
  struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
347
431
 
348
432
  LXW_ATTRIBUTE_COPY(attribute->key, key);
349
- lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%d", value);
433
+
434
+ #if defined(_MSC_VER)
435
+ lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%lld", value);
436
+ #else
437
+ lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%ld",
438
+ (long) value);
439
+ #endif
350
440
 
351
441
  return attribute;
352
442
  }
@@ -0,0 +1,42 @@
1
+ ###############################################################################
2
+ #
3
+ # Simplied Makefile to build the emyg_dtoa library for libxlsxwriter.
4
+ #
5
+
6
+ # Keep the output quiet by default.
7
+ Q=@
8
+ ifdef V
9
+ Q=
10
+ endif
11
+
12
+ UNAME := $(shell uname)
13
+
14
+ # Check for MinGW/MinGW64/Cygwin environments.
15
+ ifneq (,$(findstring MINGW, $(UNAME)))
16
+ MING_LIKE = y
17
+ endif
18
+ ifneq (,$(findstring MSYS, $(UNAME)))
19
+ MING_LIKE = y
20
+ endif
21
+ ifneq (,$(findstring CYGWIN, $(UNAME)))
22
+ MING_LIKE = y
23
+ endif
24
+
25
+ FPIC = -fPIC
26
+
27
+ # Change make options on MinGW/MinGW64/Cygwin.
28
+ ifdef MING_LIKE
29
+ FPIC =
30
+ CC = gcc
31
+ endif
32
+
33
+ all: emyg_dtoa.o emyg_dtoa.so
34
+
35
+ %.o : %.c
36
+ $(Q)$(CC) -c $(CFLAGS) $<
37
+
38
+ %.so : %.c
39
+ $(Q)$(CC) $(FPIC) -c $(CFLAGS) $< -o $@
40
+
41
+ clean:
42
+ $(Q)rm -f *.o *.so
@@ -0,0 +1,461 @@
1
+ /* emyg_dtoa.c
2
+ ** Copyright (C) 2015 Doug Currie
3
+ ** based on dtoa_milo.h
4
+ ** Copyright (C) 2014 Milo Yip
5
+ **
6
+ ** Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ ** of this software and associated documentation files (the "Software"), to deal
8
+ ** in the Software without restriction, including without limitation the rights
9
+ ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ ** copies of the Software, and to permit persons to whom the Software is
11
+ ** furnished to do so, subject to the following conditions:
12
+ **
13
+ ** The above copyright notice and this permission notice shall be included in
14
+ ** all copies or substantial portions of the Software.
15
+ **
16
+ ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ ** THE SOFTWARE.
23
+ */
24
+
25
+ /* This code is a mostly mechanical translation of Milo Yip's C++ version of
26
+ ** Grisu2 to C. For algorithm information, see Loitsch, Florian. "Printing
27
+ ** floating-point numbers quickly and accurately with integers." ACM Sigplan
28
+ ** Notices 45.6 (2010): 233-243.
29
+ */
30
+
31
+ /* Source from https://github.com/miloyip/dtoa-benchmark */
32
+
33
+
34
+ #include <assert.h>
35
+ #include <math.h>
36
+
37
+ #if defined(_MSC_VER)
38
+ #include <stdint.h>
39
+ #include <intrin.h>
40
+ #include <float.h>
41
+ #else
42
+ #include <stdint.h>
43
+ #endif
44
+
45
+ #include <string.h>
46
+
47
+ #include "emyg_dtoa.h"
48
+
49
+ #define UINT64_C2(h, l) (((uint64_t )(h) << 32) | (uint64_t )(l))
50
+
51
+ typedef struct DiyFp_s {
52
+ uint64_t f;
53
+ int e;
54
+ } DiyFp;
55
+
56
+ static const int kDiySignificandSize = 64;
57
+ static const int kDpSignificandSize = 52;
58
+ static const int kDpExponentBias = 0x3FF + 52;
59
+ static const int kDpMinExponent = -0x3FF - 52;
60
+ static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
61
+ static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
62
+ static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
63
+
64
+ static __inline DiyFp DiyFp_from_parts (uint64_t f, int e) {
65
+ DiyFp fp;
66
+ fp.f = f;
67
+ fp.e = e;
68
+ return fp;
69
+ }
70
+
71
+ DiyFp DiyFp_from_double (double d) {
72
+ DiyFp res;
73
+ int biased_e;
74
+ uint64_t significand;
75
+ union {
76
+ double d;
77
+ uint64_t u64;
78
+ } u;
79
+
80
+ u.d = d;
81
+ biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
82
+ significand = (u.u64 & kDpSignificandMask);
83
+
84
+ if (biased_e != 0) {
85
+ res.f = significand + kDpHiddenBit;
86
+ res.e = biased_e - kDpExponentBias;
87
+ }
88
+ else {
89
+ res.f = significand;
90
+ res.e = kDpMinExponent + 1;
91
+ }
92
+ return res;
93
+ }
94
+
95
+ static __inline DiyFp DiyFp_subtract (const DiyFp lhs, const DiyFp rhs) {
96
+ assert(lhs.e == rhs.e);
97
+ assert(lhs.f >= rhs.f);
98
+ return DiyFp_from_parts(lhs.f - rhs.f, lhs.e);
99
+ }
100
+
101
+ static __inline DiyFp DiyFp_multiply (const DiyFp lhs, const DiyFp rhs) {
102
+ #if defined(_MSC_VER) && defined(_M_AMD64)
103
+ uint64_t h;
104
+ uint64_t l = _umul128(lhs.f, rhs.f, &h);
105
+ /* Handle rounding. */
106
+ if (l & ((uint64_t)1u << 63))
107
+ h++;
108
+ return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
109
+ #elif ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __clang_major__ >= 9) && defined(__x86_64__))
110
+ unsigned __int128 p = (unsigned __int128 )(lhs.f) * (unsigned __int128 )(rhs.f);
111
+ uint64_t h = p >> 64;
112
+ uint64_t l = (uint64_t )(p);
113
+ /* Handle rounding. */
114
+ if (l & ((uint64_t)1u << 63))
115
+ h++;
116
+ return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
117
+ #else
118
+ const uint64_t M32 = 0xFFFFFFFF;
119
+ const uint64_t a = lhs.f >> 32;
120
+ const uint64_t b = lhs.f & M32;
121
+ const uint64_t c = rhs.f >> 32;
122
+ const uint64_t d = rhs.f & M32;
123
+ const uint64_t ac = a * c;
124
+ const uint64_t bc = b * c;
125
+ const uint64_t ad = a * d;
126
+ const uint64_t bd = b * d;
127
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
128
+ tmp += 1U << 31; /* mult_round */
129
+ return DiyFp_from_parts(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), lhs.e + rhs.e + 64);
130
+ #endif
131
+ }
132
+
133
+ static __inline DiyFp Normalize (const DiyFp lhs) {
134
+ #if defined(_MSC_VER) && defined(_M_AMD64)
135
+ unsigned long index;
136
+ _BitScanReverse64(&index, lhs.f);
137
+ return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
138
+ #elif defined(__GNUC__)
139
+ int s = __builtin_clzll(lhs.f);
140
+ return DiyFp_from_parts(lhs.f << s, lhs.e - s);
141
+ #else
142
+ DiyFp res = lhs;
143
+ while (!(res.f & kDpHiddenBit)) {
144
+ res.f <<= 1;
145
+ res.e--;
146
+ }
147
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
148
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
149
+ return res;
150
+ #endif
151
+ }
152
+
153
+ static __inline DiyFp NormalizeBoundary (const DiyFp lhs) {
154
+ #if defined(_MSC_VER) && defined(_M_AMD64)
155
+ unsigned long index;
156
+ _BitScanReverse64(&index, lhs.f);
157
+ return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
158
+ #else
159
+ DiyFp res = lhs;
160
+ while (!(res.f & (kDpHiddenBit << 1))) {
161
+ res.f <<= 1;
162
+ res.e--;
163
+ }
164
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
165
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
166
+ return res;
167
+ #endif
168
+ }
169
+
170
+ static __inline void NormalizedBoundaries (DiyFp lhs, DiyFp* minus, DiyFp* plus) {
171
+ DiyFp pl = NormalizeBoundary(DiyFp_from_parts((lhs.f << 1) + 1, lhs.e - 1));
172
+ DiyFp mi = (lhs.f == kDpHiddenBit)
173
+ ? DiyFp_from_parts((lhs.f << 2) - 1, lhs.e - 2)
174
+ : DiyFp_from_parts((lhs.f << 1) - 1, lhs.e - 1);
175
+ mi.f <<= mi.e - pl.e;
176
+ mi.e = pl.e;
177
+ *plus = pl;
178
+ *minus = mi;
179
+ }
180
+
181
+ static __inline DiyFp GetCachedPower (int e, int* K) {
182
+ unsigned index;
183
+
184
+ /* 10^-348, 10^-340, ..., 10^340 */
185
+ static const uint64_t kCachedPowers_F[] = {
186
+ UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
187
+ UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
188
+ UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
189
+ UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
190
+ UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
191
+ UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
192
+ UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
193
+ UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
194
+ UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
195
+ UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
196
+ UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
197
+ UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
198
+ UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
199
+ UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
200
+ UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
201
+ UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
202
+ UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
203
+ UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
204
+ UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
205
+ UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
206
+ UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
207
+ UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
208
+ UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
209
+ UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
210
+ UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
211
+ UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
212
+ UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
213
+ UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
214
+ UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
215
+ UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
216
+ UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
217
+ UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
218
+ UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
219
+ UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
220
+ UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
221
+ UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
222
+ UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
223
+ UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
224
+ UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
225
+ UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
226
+ UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
227
+ UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
228
+ UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
229
+ UINT64_C2(0xaf87023b, 0x9bf0ee6b)
230
+ };
231
+ static const int16_t kCachedPowers_E[] = {
232
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
233
+ -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
234
+ -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
235
+ -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
236
+ -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
237
+ 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
238
+ 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
239
+ 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
240
+ 907, 933, 960, 986, 1013, 1039, 1066
241
+ };
242
+
243
+ /* dk must be positive, so can do ceiling in positive */
244
+ double dk = (-61 - e) * 0.30102999566398114 + 347;
245
+ int k = (int )(dk);
246
+ if (k != dk)
247
+ k++;
248
+
249
+ index = (unsigned )((k >> 3) + 1);
250
+ /* decimal exponent no need lookup table */
251
+ *K = -(-348 + (int )(index << 3));
252
+
253
+ assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
254
+ return DiyFp_from_parts(kCachedPowers_F[index], kCachedPowers_E[index]);
255
+ }
256
+
257
+ static __inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
258
+ while (rest < wp_w && delta - rest >= ten_kappa &&
259
+ (rest + ten_kappa < wp_w || /* closer */
260
+ wp_w - rest > rest + ten_kappa - wp_w)) {
261
+ buffer[len - 1]--;
262
+ rest += ten_kappa;
263
+ }
264
+ }
265
+
266
+ static __inline unsigned CountDecimalDigit32(uint32_t n) {
267
+ /* Simple pure C++ implementation was faster than __builtin_clz version in this situation. */
268
+ if (n < 10) return 1;
269
+ if (n < 100) return 2;
270
+ if (n < 1000) return 3;
271
+ if (n < 10000) return 4;
272
+ if (n < 100000) return 5;
273
+ if (n < 1000000) return 6;
274
+ if (n < 10000000) return 7;
275
+ if (n < 100000000) return 8;
276
+ if (n < 1000000000) return 9;
277
+ return 10;
278
+ }
279
+
280
+ static __inline void DigitGen(const DiyFp W, const DiyFp Mp, uint64_t delta, char* buffer, int* len, int* K) {
281
+ static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
282
+ const DiyFp one = DiyFp_from_parts((uint64_t )(1) << -Mp.e, Mp.e);
283
+ const DiyFp wp_w = DiyFp_subtract(Mp, W);
284
+ uint32_t p1 = (uint32_t )(Mp.f >> -one.e);
285
+ uint64_t p2 = Mp.f & (one.f - 1);
286
+ int kappa = (int )(CountDecimalDigit32(p1));
287
+ *len = 0;
288
+
289
+ while (kappa > 0) {
290
+ uint32_t d;
291
+ uint64_t tmp;
292
+ switch (kappa) {
293
+ case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
294
+ case 9: d = p1 / 100000000; p1 %= 100000000; break;
295
+ case 8: d = p1 / 10000000; p1 %= 10000000; break;
296
+ case 7: d = p1 / 1000000; p1 %= 1000000; break;
297
+ case 6: d = p1 / 100000; p1 %= 100000; break;
298
+ case 5: d = p1 / 10000; p1 %= 10000; break;
299
+ case 4: d = p1 / 1000; p1 %= 1000; break;
300
+ case 3: d = p1 / 100; p1 %= 100; break;
301
+ case 2: d = p1 / 10; p1 %= 10; break;
302
+ case 1: d = p1; p1 = 0; break;
303
+ default:
304
+ #if defined(_MSC_VER)
305
+ __assume(0);
306
+ #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
307
+ __builtin_unreachable();
308
+ #else
309
+ d = 0;
310
+ #endif
311
+ }
312
+ if (d || *len)
313
+ buffer[(*len)++] = '0' + (char )(d);
314
+ kappa--;
315
+ tmp = ((uint64_t )(p1) << -one.e) + p2;
316
+ if (tmp <= delta) {
317
+ *K += kappa;
318
+ GrisuRound(buffer, *len, delta, tmp, (uint64_t )(kPow10[kappa]) << -one.e, wp_w.f);
319
+ return;
320
+ }
321
+ }
322
+
323
+ /* kappa = 0 */
324
+ for (;;) {
325
+ char d;
326
+ p2 *= 10;
327
+ delta *= 10;
328
+ d = (char )(p2 >> -one.e);
329
+ if (d || *len)
330
+ buffer[(*len)++] = '0' + d;
331
+ p2 &= one.f - 1;
332
+ kappa--;
333
+ if (p2 < delta) {
334
+ *K += kappa;
335
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
336
+ return;
337
+ }
338
+ }
339
+ }
340
+
341
+ static __inline void Grisu2(double value, char* buffer, int* length, int* K) {
342
+ const DiyFp v = DiyFp_from_double(value);
343
+ DiyFp c_mk;
344
+ DiyFp W;
345
+ DiyFp w_m, w_p;
346
+ DiyFp Wp;
347
+ DiyFp Wm;
348
+ NormalizedBoundaries(v, &w_m, &w_p);
349
+
350
+ c_mk = GetCachedPower(w_p.e, K);
351
+ W = DiyFp_multiply(Normalize(v), c_mk);
352
+ Wp = DiyFp_multiply(w_p, c_mk);
353
+ Wm = DiyFp_multiply(w_m, c_mk);
354
+ Wm.f++;
355
+ Wp.f--;
356
+ DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
357
+ }
358
+
359
+ static __inline const char* GetDigitsLut(void) {
360
+ static const char cDigitsLut[200] = {
361
+ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
362
+ '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
363
+ '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
364
+ '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
365
+ '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
366
+ '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
367
+ '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
368
+ '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
369
+ '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
370
+ '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
371
+ };
372
+ return cDigitsLut;
373
+ }
374
+
375
+ static __inline void WriteExponent(int K, char* buffer) {
376
+ if (K < 0) {
377
+ *buffer++ = '-';
378
+ K = -K;
379
+ }
380
+ else {
381
+ *buffer++ = '+';
382
+ }
383
+
384
+ if (K >= 100) {
385
+ char* d;
386
+ *buffer++ = '0' + (char )(K / 100);
387
+ K %= 100;
388
+ d = (char*)GetDigitsLut() + K * 2;
389
+ *buffer++ = d[0];
390
+ *buffer++ = d[1];
391
+ }
392
+ else if (K >= 10) {
393
+ const char* d = GetDigitsLut() + K * 2;
394
+ *buffer++ = d[0];
395
+ *buffer++ = d[1];
396
+ }
397
+ else
398
+ *buffer++ = '0' + (char )(K);
399
+
400
+ *buffer = '\0';
401
+ }
402
+
403
+ static __inline void Prettify(char* buffer, int length, int k) {
404
+ int i;
405
+ const int kk = length + k; /* 10^(kk-1) <= v < 10^kk */
406
+
407
+ if (length <= kk && kk <= 17) {
408
+ /* 1234e7 -> 12340000000 */
409
+ for (i = length; i < kk; i++)
410
+ buffer[i] = '0';
411
+ buffer[kk] = '\0';
412
+ }
413
+ else if (0 < kk && kk <= 17) {
414
+ /* 1234e-2 -> 12.34 */
415
+ memmove(&buffer[kk + 1], &buffer[kk], length - kk);
416
+ buffer[kk] = '.';
417
+ buffer[length + 1] = '\0';
418
+ }
419
+ else if (-6 < kk && kk <= 0) {
420
+ /* 1234e-6 -> 0.001234 */
421
+ const int offset = 2 - kk;
422
+ memmove(&buffer[offset], &buffer[0], length);
423
+ buffer[0] = '0';
424
+ buffer[1] = '.';
425
+ for (i = 2; i < offset; i++)
426
+ buffer[i] = '0';
427
+ buffer[length + offset] = '\0';
428
+ }
429
+ else if (length == 1) {
430
+ /* 1E30 */
431
+ buffer[1] = 'E';
432
+ WriteExponent(kk - 1, &buffer[2]);
433
+ }
434
+ else {
435
+ /* 1234E30 -> 1.234E33 */
436
+ memmove(&buffer[2], &buffer[1], length - 1);
437
+ buffer[1] = '.';
438
+ buffer[length + 1] = 'E';
439
+ WriteExponent(kk - 1, &buffer[0 + length + 2]);
440
+ }
441
+ }
442
+
443
+ void emyg_dtoa (double value, char* buffer) {
444
+ int length, K;
445
+ /* Not handling NaN and inf */
446
+ assert(!isnan(value));
447
+ assert(!isinf(value));
448
+
449
+ if (value == 0) {
450
+ buffer[0] = '0';
451
+ buffer[1] = '\0';
452
+ }
453
+ else {
454
+ if (value < 0) {
455
+ *buffer++ = '-';
456
+ value = -value;
457
+ }
458
+ Grisu2(value, buffer, &length, &K);
459
+ Prettify(buffer, length, K);
460
+ }
461
+ }
@@ -0,0 +1,26 @@
1
+ /* emyg_dtoa.h
2
+ ** Copyright (C) 2015 Doug Currie
3
+ ** based on dtoa_milo.h
4
+ ** Copyright (C) 2014 Milo Yip
5
+ **
6
+ ** Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ ** of this software and associated documentation files (the "Software"), to deal
8
+ ** in the Software without restriction, including without limitation the rights
9
+ ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ ** copies of the Software, and to permit persons to whom the Software is
11
+ ** furnished to do so, subject to the following conditions:
12
+ **
13
+ ** The above copyright notice and this permission notice shall be included in
14
+ ** all copies or substantial portions of the Software.
15
+ **
16
+ ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ ** THE SOFTWARE.
23
+ */
24
+
25
+ /* Source from https://github.com/miloyip/dtoa-benchmark */
26
+ void emyg_dtoa (double value, char* buffer);