-
-
Notifications
You must be signed in to change notification settings - Fork 370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved table encoding code to handle sparse arrays. #28
base: master
Are you sure you want to change the base?
Conversation
…numbers are encoding improved.
Hello! This would be nice change, but
Why is this beneficial? |
… The array detection code now allows for the array to have a key n with a number value to detect the array length.
Fixed that. Now arrays can be specified through table.pack. |
json.lua
Outdated
@@ -108,7 +119,7 @@ local function encode_number(val) | |||
if val ~= val or val <= -math.huge or val >= math.huge then | |||
error("unexpected number value '" .. tostring(val) .. "'") | |||
end | |||
return string.format("%.14g", val) | |||
return tostring(val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unreliable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't understand. Perhaps a more useful/productive comment? Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, that was indeed too short to be useful. The documentation of tostring
says:
Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, use string.format.
It doesn't guarantee anything. It could output the number with arbitrarily poor precision, or it could use an arbitrary format (which need not be valid JSON). (In practice, it does indeed behave quite reasonable, but you shouldn't rely on this; it should also be noted that it is not "lossless" in practice, it rounds (albeit neither is the current method - 14 digits aren't enough).)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for explaining it. I see. I remember I had changed it to make a certain case work properly when I was using it in the oauth2 module. Unfortunately I did not document why I changed it. I think I switched it back in the repository for now.
json.lua
Outdated
-- Encode | ||
for i, v in ipairs(val) do | ||
table.insert(res, encode(v, stack)) | ||
for i=1,length do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix your formatting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes fixed it for this function only. Tab structure in the original file is different than my tool. Didn't change the whole file.
json.lua
Outdated
end | ||
stack[val] = nil | ||
return "[" .. table.concat(res, ",") .. "]" | ||
|
||
else | ||
-- Treat as an object | ||
for k, v in pairs(val) do | ||
--[[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dirty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't understand. Perhaps a more useful/productive comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outcommented code is dirty; it's effectively leaving "trash" around in the codebase. If it isn't needed anymore, remove it; it'll still be in the Git history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thanks. I usually keep some portions in my code to see some history immediately but you are right it is in the version history. I cleaned it up.
-- Check whether to treat as a array or object | ||
local array = true | ||
local length = 0 | ||
local nLen = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered the worst-case this might create: What if I serialize {[1e9] = true}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missed all these. Revisiting after a long time. Thanks for catching that. Had not considered it at all. Been using it, did not have issues. Fixed it in the next commit by preventing sparse arrays greater than 100 (arbitrarility) length getting through. Seems like other json modules also handle sparse arrays in a undefined way. 100 should be good for many cases I suppose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a tricky issue, and behavior varies wildly. I believe ideally it should be left up to the user. Perhaps use something like a "density" factor as a threshold?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added a variable called SPARSELIMIT in the module that the user can change after requiring the module to change it. Default set it to 100.
@appgurueu You're coming off as unnecessarily rude. |
json.lua
Outdated
local nLen = 0 | ||
local count = 0 | ||
for k,v in pairs(val) do | ||
if (type(k) ~= "number" or k<=0) and not (k == "n" and type(v) == "number") then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about fractional keys, like 4.2
? I think you also need a check like k % 1 == 0
or math.floor(k) == k
to check that k
is (not) an integer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, added k%1 ~= 0 in the condition.
I'm not sure what you consider to be rude about my review. I made three comments:
This was intended just as very "direct" feedback from a quick look. If I came off as rude to @aryajur, that was not my intention, and I apologize for that. |
I appreciate your feedback. Would always want to improve my work. |
…to control the length threshold of sparse arrays. Some bug fixes and improvements as suggested by @appgurueu
By going through the table before to get the maximum index we can handle sparse arrays. Also tostring seems to work better by maintaining float and integer number conversion.