aboutsummaryrefslogtreecommitdiff
path: root/gnu/packages/patches/sajson-for-gemmi-numbers-as-strings.patch
blob: 6f476b8583fb032598a10688ce43b06f6117ef28 (about) (plain)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
Patch for gemmi: Keep numbers in JSON file as strings.

Adapted from this commit of the bundled fork of sajson in gemmi:
https://github.com/project-gemmi/gemmi/commit/fccbca4f6040364ba708613e1429c2251872240d

diff -ur a/include/sajson.h b/include/sajson.h
--- a/include/sajson.h
+++ b/include/sajson.h
@@ -411,43 +411,6 @@
 };
 } // namespace internal
 
-namespace integer_storage {
-enum { word_length = 1 };
-
-inline int load(const size_t* location) {
-    int value;
-    memcpy(&value, location, sizeof(value));
-    return value;
-}
-
-inline void store(size_t* location, int value) {
-    // NOTE: Most modern compilers optimize away this constant-size
-    // memcpy into a single instruction. If any don't, and treat
-    // punning through a union as legal, they can be special-cased.
-    static_assert(
-        sizeof(value) <= sizeof(*location),
-        "size_t must not be smaller than int");
-    memcpy(location, &value, sizeof(value));
-}
-} // namespace integer_storage
-
-namespace double_storage {
-enum { word_length = sizeof(double) / sizeof(size_t) };
-
-inline double load(const size_t* location) {
-    double value;
-    memcpy(&value, location, sizeof(double));
-    return value;
-}
-
-inline void store(size_t* location, double value) {
-    // NOTE: Most modern compilers optimize away this constant-size
-    // memcpy into a single instruction. If any don't, and treat
-    // punning through a union as legal, they can be special-cased.
-    memcpy(location, &value, sizeof(double));
-}
-} // namespace double_storage
-
 /// Represents a JSON value.  First, call get_type() to check its type,
 /// which determines which methods are available.
 ///
@@ -585,70 +548,10 @@
         return length;
     }
 
-    /// If a numeric value was parsed as a 32-bit integer, returns it.
-    /// Only legal if get_type() is TYPE_INTEGER.
-    int get_integer_value() const {
-        assert_tag(tag::integer);
-        return integer_storage::load(payload);
-    }
-
-    /// If a numeric value was parsed as a double, returns it.
-    /// Only legal if get_type() is TYPE_DOUBLE.
-    double get_double_value() const {
-        assert_tag(tag::double_);
-        return double_storage::load(payload);
-    }
-
-    /// Returns a numeric value as a double-precision float.
-    /// Only legal if get_type() is TYPE_INTEGER or TYPE_DOUBLE.
-    double get_number_value() const {
-        assert_tag_2(tag::integer, tag::double_);
-        if (value_tag == tag::integer) {
-            return get_integer_value();
-        } else {
-            return get_double_value();
-        }
-    }
-
-    /// Returns true and writes to the output argument if the numeric value
-    /// fits in a 53-bit integer.  This is useful for timestamps and other
-    /// situations where integral values with greater than 32-bit precision
-    /// are used, as 64-bit values are not understood by all JSON
-    /// implementations or languages.
-    /// Returns false if the value is not an integer or not in range.
-    /// Only legal if get_type() is TYPE_INTEGER or TYPE_DOUBLE.
-    bool get_int53_value(int64_t* out) const {
-        // Make sure the output variable is always defined to avoid any
-        // possible situation like
-        // https://gist.github.com/chadaustin/2c249cb850619ddec05b23ca42cf7a18
-        *out = 0;
-
-        assert_tag_2(tag::integer, tag::double_);
-        switch (value_tag) {
-        case tag::integer:
-            *out = get_integer_value();
-            return true;
-        case tag::double_: {
-            double v = get_double_value();
-            if (v < -(1LL << 53) || v > (1LL << 53)) {
-                return false;
-            }
-            int64_t as_int = static_cast<int64_t>(v);
-            if (as_int != v) {
-                return false;
-            }
-            *out = as_int;
-            return true;
-        }
-        default:
-            return false;
-        }
-    }
-
     /// Returns the length of the string.
     /// Only legal if get_type() is TYPE_STRING.
     size_t get_string_length() const {
-        assert_tag(tag::string);
+        assert_tag_3(tag::string, tag::integer, tag::double_);
         return payload[1] - payload[0];
     }
 
@@ -659,7 +562,7 @@
     /// embedded NULs.
     /// Only legal if get_type() is TYPE_STRING.
     const char* as_cstring() const {
-        assert_tag(tag::string);
+        assert_tag_3(tag::string, tag::integer, tag::double_);
         return text + payload[0];
     }
 
@@ -667,7 +570,7 @@
     /// Returns a string's value as a std::string.
     /// Only legal if get_type() is TYPE_STRING.
     std::string as_string() const {
-        assert_tag(tag::string);
+        assert_tag_3(tag::string, tag::integer, tag::double_);
         return std::string(text + payload[0], text + payload[1]);
     }
 #endif
@@ -690,6 +593,10 @@
         assert(e1 == value_tag || e2 == value_tag);
     }
 
+    void assert_tag_3(tag e1, tag e2, tag e3) const {
+        assert(e1 == value_tag || e2 == value_tag || e3 == value_tag);
+    }
+
     void assert_in_bounds(size_t i) const { assert(i < get_length()); }
 
     const tag value_tag;
@@ -2059,6 +1966,8 @@
     std::pair<char*, internal::tag> parse_number(char* p) {
         using internal::tag;
 
+	size_t start = p - input.get_data();
+
         // Assume 32-bit, two's complement integers.
         static constexpr unsigned RISKY = INT_MAX / 10u;
         unsigned max_digit_after_risky = INT_MAX % 10u;
@@ -2235,23 +2144,18 @@
                 u = 0u - u;
             }
         }
+
+        bool success;
+        size_t* out = allocator.reserve(2, &success);
+        if (SAJSON_UNLIKELY(!success)) {
+            return std::make_pair(oom(p, "number"), tag::null);
+        }
+        out[0] = start;
+        out[1] = p - input.get_data();
+
         if (try_double) {
-            bool success;
-            size_t* out
-                = allocator.reserve(double_storage::word_length, &success);
-            if (SAJSON_UNLIKELY(!success)) {
-                return std::make_pair(oom(p, "double"), tag::null);
-            }
-            double_storage::store(out, d);
             return std::make_pair(p, tag::double_);
         } else {
-            bool success;
-            size_t* out
-                = allocator.reserve(integer_storage::word_length, &success);
-            if (SAJSON_UNLIKELY(!success)) {
-                return std::make_pair(oom(p, "integer"), tag::null);
-            }
-            integer_storage::store(out, static_cast<int>(u));
             return std::make_pair(p, tag::integer);
         }
     }