Issue with parsing unsigned numbers
Description
Hello! First of all, I'd like to thank you once again for improving this library!❤️
I have a small issue with loading unsigned numbers in a document - for example, when trying to load a document that contains a number which is a 64-bit xxHash cipher, I get the following exception:

It seems that the project doesn't currently support unsigned numbers (std::uint64_t). I tried to add support myself, but the end result always ends in failure.
However, I've made a few potentially useful changes that could make it easier to introduce a new type - unless we come up with some other solution?
Reproduction steps
Please use this source code:
#include <iostream>
#include <fkYAML/node.hpp>
int
main()
{
auto yaml = fkyaml::node::deserialize("x: 15745692345339290292");
std::cout << yaml["x"].as_int();
}
Expected vs. actual results
Expected result is parse correctly unsigned integer, actual result is an exception.
Minimal code example
I attached earlier
Error messages
I attached earlier
Compiler and operating system
Windows 11, Latest MSVC
Library version
develop
Validation
- [x] The bug also occurs if the latest version from the
developbranch is used. - [ ] I can successfully compile and run the unit tests.
Hi, did you ever solve this? I need to save a uint64_t and I don't know how. Thanks!
Hello, I'll try to deal again with this issue, if I succeed I'll let you know!
Hi @Sebight, I have good news. I managed to add basic support for unsigned numbers. For now, it works only with to_node, so from_node might still be an issue, but with the new functions as_uint() and is_unsigned_integer() we can already extract unsigned values from a node.
I haven't written unit tests yet because I don't have enough time - if you'd like to help, I'd really appreciate it! Anyway, here's a simple example:
#include <iostream>
#include <fkYAML/node.hpp>
int
main()
{
auto test = fkyaml::node::deserialize("x: 2147483648\ny: 15745692345339290292");
std::cout << test["x"].as_uint() << '\n'; // 2147483648
std::cout << test["x"].is_integer() << '\n'; // 1
std::cout << test["x"].is_unsigned_integer() << "\n\n"; // 1 (integer is treated as unsigned like nlohmann)
std::cout << test["y"].as_uint() << '\n'; // 15745692345339290292
std::cout << test["y"].is_integer() << '\n'; // 0
std::cout << test["y"].is_unsigned_integer() << "\n\n"; // 1
}
Hello @Sebight. Did you tested my branch? Thank you 😄
Hi @sndth, really sorry, I have decided in the end to go with JSON. I could still test the branch when I find a moment, but I won't probably be needing a yaml library in the near future. 😅
Hey @sndth, I thought I wouldn't run into this problem because I was using get_value<uint64_t>() instead of as_int(), but if my ID has 20 digits (most significant bit set to 1), it fails to parse. But if it has 19, it doesn't fail, probably because it fits in a int64_t.
Is this a bug as well? The easiest fix for me would be to truncate the value, I guess there would be no problems with conflicts even when losing a bit.
Hello @MirrasHue, thanks for you report! Currently I recommend using as_uint() from my branch. I'll take a look into the get_value function. Of course, this is a bug :(
Hey @sndth, I thought I wouldn't run into this problem because I was using
get_value<uint64_t>()instead ofas_int(), but if my ID has 20 digits (most significant bit set to 1), it fails to parse. But if it has 19, it doesn't fail, probably because it fits in a int64_t.Is this a bug as well? The easiest fix for me would be to truncate the value, I guess there would be no problems with conflicts even when losing a bit.
Wait, max value of uint64_t is 9223372036854775807 (19 digits), so when you try to parse 20 digits number, output should be in a string haha
It's that value times 2:
you can see in the print the most significant bit is not set.
Edit: Ah, it doesn't necessarily need to have 20 digits. Just be greater than 2^63 (which means the first digit is set).
Looking at the source code, I see the problem. Internally, get_value<uint64_t>() calls as_int():
struct from_node_int_helper {
/// @brief Convert node's integer value to the target integer type.
/// @param n A node object.
/// @return An integer value converted from the node's integer value.
static IntType convert(const BasicNodeType& n) {
return n.as_int();
}
};
I tried to implement to_node/from_node taking a uint64 and converting it to string and back to an integer with stoull(), but it didn't work.
One approach that worked was this one:
if(entity["ID"] != nullptr)
{
if(entity["ID"].is_integer())
id = entity["ID"].get_value<uint64>();
else
id = std::stoull(entity["ID"].get_value<std::string>());
}