* gnu/packages/cpp.scm (sajson-for-gemmi): New variable. Signed-off-by: Liliana Marie Prikler <liliana.prikler@gmail.com>
		
			
				
	
	
		
			195 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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);
 | |
|          }
 | |
|      }
 |