fast_excel 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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);