Open oscbyspro opened 3 months ago
I'll work on this for a while. Maybe I'll fix Apple's JSON decoder while I'm at it.
:magic_wand: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles:
So it turns out that you can clamp the exponent to the bounds of Int, if the maximum number of characters is Int.max. But this only works if you normalize the integer, fraction, and exponent parts in a specific way. Otherwise, the saturation may introduce lossy behavior near Int.max character inputs. You'll never actually parse inputs that big, but there's a proper way of doing it with signed same-size integers. I considered using sign-magnitude to get an extra bit of space, but then I thought of the normalization thing. Signed integer buffer sizes save the day again.
But a sign-magnitude exponent is simpler in practice because applying the normalization bias correctly is nontrivial.
I want to support JSON, JSON5 and whatever Swift is doing.
The JSON ones work, but I just realized that Swift parses this thing: {sign}0x{hex}.{hex}p{sign}{decimal}.
I'll totally parse that too, but mixing hex and decimal is rude :(
Sign and magnitude exponent saturation does not work in the case of 0x{hex}.{hex}p{decimal} since the exponent part respresents a binary multiplier. You need more bits, basically. It might be simpler to just limit the input size to some silly-big-but-small-enough number or settle on a larger exponent type. Hm.
So, I bascally have a lossless strtod
-as-int now. I'll just have to add some more tests and clean it up a bit. Additionally, while I'm sure I'm the last one to figure this out by myself, you can skip a bunch of comparisons by lowercasing bytes as (x|32)
. It's quite neat and probably by design.
Hm. Theres a tricky edge case for integer sizes that aren't multiples of 4. Adding a hexadecimal digit might overflow a significand that is brought back into range by the binary exponent. Remember that strtod
uses a hex-hex-bin format. I have banned silly integers for a reason in this project, but I suppose I might want to solve it regardless.
I've been writing it in Swift proper with thoughts of porting it to this project, but the opposite seems wiser given that I have infrastructure I might want to evolve with the solution. Zzz. At least I found some edge cases that only applies to the former.
I wonder if the exponent type in BinaryInteger/power(_:) (#53) should be UX
. I think there's some merit in using Magnitude
but the shift-by-1 approach doesn't scale well beyond register sizes and arbitrary integers cannot allocate beyond that. Hm.
I'm sure I'll need to losslessly parse arbitrary floating-point numbers at some point.