forked from facebook/hermes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dtoa.h
163 lines (145 loc) · 6.49 KB
/
dtoa.h
1
2
3
4
5
6
7
8
9
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// dtoa doesn't provide a header file so this simple one was created.
#ifndef HERMES_DTOA_DTOA_H
#define HERMES_DTOA_DTOA_H
#ifdef __cplusplus
extern "C" {
#endif
/// dtoa functions need to allocate memory and that job is handled by the dtoa
/// allocator. \c dtoa_alloc is an opaque struct representing the allocator. It
/// is created by calling \c dtoa_alloc_init() with a pointer to a memory
/// buffer declared with \c DECL_DTOA_ALLOC_MEM(name, size).
///
/// The allocator metadata itself is placed in that memory buffer and the rest
/// of it is used to satisfy memory allocations. If it is not enough, additional
/// allocations are made in the regular heap with malloc()/free(). So, the
/// larger the buffer declared by \c DECL_DTOA_ALLOC_MEM(), the less probability
/// there that a heap allocation will be needed.
///
/// The allocator is not thread safe, so we must guarantee that it is used only
/// by one thread a time. Usually we just create it on the stack (which is very
/// fast), but it could live in other places, as long as the single thread
/// requirement is satisfied.
///
/// The allocator metadata itself is less than 128 bytes - the rest is the
/// "allocation buffer". The dtoa documentation states that 2304 byte allocation
/// buffer is sufficient for most cases except the unusual ones, and a 7400 byte
/// allocation buffer is sufficient for all cases.
///
/// We don't need to avoid heap allocation at all costs, so we have chosen a
/// total allocator size of 1200 bytes, which seems to avoid heap allocations
/// for "normal" cases.
typedef struct dtoa_alloc dtoa_alloc;
/// The minimal size of the dtoa allocator memory buffer. The metadata is less
/// than 128 bytes and the rest is available to satisfy dtoa allocations.
#define DTOA_ALLOC_MIN_SIZE 256
/// The default size of the dtoa allocator memory buffer, which we use when
/// declaring it on the stack. The value attempts to find balance between
/// excessive stack consumption and avoiding allocations for "normal" cases.
#define DTOA_ALLOC_DEFAULT_SIZE 1200
/// This macro is used to declare a memory buffer for the dtoa allocator. Most
/// of all it ensures that the memory is properly aligned. The variable declared
/// by this macro is then passed to \c dtoa_alloc_init().
#define DECL_DTOA_ALLOC_MEM(name, bytelen) \
union { \
void *p; \
double d; \
long long l; \
char mem[(bytelen)]; \
} name
/// Initialize an allocator using the specified memory buffer, and return a
/// pointer to the allocator. Note that this does not stipulate that the
/// returned pointer will equal \c mem.
dtoa_alloc *dtoa_alloc_init(void *mem, int bytelen);
/// Destroy the previously initialized allocator. Primarily, this call frees
/// any heap allocations in the allocator.
void dtoa_alloc_done(dtoa_alloc *dalloc);
/// Converts double into ascii string.
/// \param dd the double to convert.
/// \param mode the rounding mode, 0 for default.<ul>
/// <li>0 ==> shortest string that yields d when read in
/// and rounded to nearest.
/// <li>1 ==> like 0, but with Steele & White stopping rule;
/// e.g. with IEEE P754 arithmetic , mode 0 gives
/// 1e23 whereas mode 1 gives 9.999999999999999e22.
/// <li>2 ==> max(1,ndigits) significant digits. This gives a
/// return value similar to that of ecvt, except
/// that trailing zeros are suppressed.
/// <li>3 ==> through ndigits past the decimal point. This
/// gives a return value similar to that from fcvt,
/// except that trailing zeros are suppressed, and
/// ndigits can be negative.
/// <li>4,5 ==> similar to 2 and 3, respectively, but (in
/// round-nearest mode) with the tests of mode 0 to
/// possibly return a shorter string that rounds to d.
/// With IEEE arithmetic and compilation with
/// -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
/// as modes 2 and 3 when FLT_ROUNDS != 1.
/// <li>6-9 ==> Debugging modes similar to mode - 4: don't try
/// fast floating-point estimate (if applicable).
/// <li>Values of mode other than 0-9 are treated as mode 0.
/// </ul>
/// \param ndigits number of digits of precision, 0 for default.
/// \param decpt where to store position of the decimal. (n in ES5.1 9.8.1)
/// \param sign location to store 1 if negative number, 0 if positive number.
/// \param rve location to store pointer to the end of the returned string.
/// \return string representation of s in ES5.1 9.8.1
char *g_dtoa(
dtoa_alloc *dalloc,
double dd,
int mode,
int ndigits,
int *decpt,
int *sign,
char **rve);
/// Same as dtoa, but #defines ROUND_BIASED, which enables the mode which is
/// used for getting results with a fixed number of digits after the decimal.
/// It also modifies a check in dtoa (see the NOTE in dtoa_fixed.c),
/// which ensures that 0.5 does not get flushed to 0, but rather rounds up to 1.
/// A separate function is necessary because dtoa needs compilation flags
/// to change options and provides no runtime means of doing so,
/// and modification of the code was needed to ensure correctly biased rounding.
char *dtoa_fixedpoint(
dtoa_alloc *dalloc,
double dd,
int mode,
int ndigits,
int *decpt,
int *sign,
char **rve);
/// Free the result of \c g_dtoa() and \c dtoa_fixedpoint().
void g_freedtoa(dtoa_alloc *dalloc, char *);
char *g_fmt(char *, double);
double hermes_g_strtod(const char *s00, char **se);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
/// A convenience RAII wrapper around a dtoa allocator. The usage should be
/// self-explanatory. Declare it on the stack (or as a class member), supplying
/// the memory buffer size, and pass it to the dtoa functions.
template <int bytelen = DTOA_ALLOC_DEFAULT_SIZE>
class DtoaAllocator {
public:
DtoaAllocator(const DtoaAllocator &) = delete;
void operator=(const DtoaAllocator &) = delete;
DtoaAllocator() {
dalloc_ = dtoa_alloc_init(&mem_, bytelen);
}
~DtoaAllocator() {
dtoa_alloc_done(dalloc_);
}
operator dtoa_alloc *() {
return dalloc_;
}
private:
DECL_DTOA_ALLOC_MEM(mem_, bytelen);
dtoa_alloc *dalloc_;
};
#endif
#endif // HERMES_DTOA_DTOA_H