Skip to content

Commit e7a199a

Browse files
committed
Reduce memory usage in json stack
Avoid additional cons on objects and arrays by using tuples for objects (uses 3 words instead of 4 words) and avoiding a double cons on arrays (uses 2 words).
1 parent 50d69f7 commit e7a199a

1 file changed

Lines changed: 11 additions & 15 deletions

File tree

lib/stdlib/src/json.erl

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ Both encoder and decoder fully conform to
3333
standards. The decoder is tested using [JSONTestSuite](https://github.com/nst/JSONTestSuite).
3434
""".
3535

36-
-dialyzer(no_improper_lists).
37-
3836
-export([
3937
encode/1, encode/2,
4038
encode_value/2,
@@ -806,9 +804,6 @@ steps(N) -> ["\n", lists:duplicate(N, " ")].
806804
%% Decoding implementation
807805
%%
808806

809-
-define(ARRAY, array).
810-
-define(OBJECT, object).
811-
812807
-type from_binary_fun() :: fun((binary()) -> dynamic()).
813808
-type array_start_fun() :: fun((Acc :: dynamic()) -> ArrayAcc :: dynamic()).
814809
-type array_push_fun() :: fun((Value :: dynamic(), Acc :: dynamic()) -> NewAcc :: dynamic()).
@@ -844,7 +839,7 @@ steps(N) -> ["\n", lists:duplicate(N, " ")].
844839
}).
845840

846841
-type acc() :: dynamic().
847-
-type stack() :: [?ARRAY | ?OBJECT | binary() | acc()].
842+
-type stack() :: [] | {acc(), stack()} | nonempty_improper_list(acc(), stack()).
848843
-type decode() :: #decode{}.
849844

850845
-opaque continuation_state() :: tuple().
@@ -1359,8 +1354,8 @@ array_start(<<>>, Original, Skip, Acc, Stack, Decode, Len) ->
13591354
unexpected(Original, Skip, Acc, Stack, Decode, Len, 0, value);
13601355
array_start(Rest, Original, Skip, OldAcc, Stack, Decode, Len) ->
13611356
case Decode#decode.array_start of
1362-
undefined -> value(Rest, Original, Skip+Len, [], [?ARRAY, OldAcc | Stack], Decode);
1363-
Fun -> value(Rest, Original, Skip+Len, Fun(OldAcc), [?ARRAY, OldAcc | Stack], Decode)
1357+
undefined -> value(Rest, Original, Skip+Len, [], [OldAcc | Stack], Decode);
1358+
Fun -> value(Rest, Original, Skip+Len, Fun(OldAcc), [OldAcc | Stack], Decode)
13641359
end.
13651360

13661361
array_push(<<Byte, Rest/bits>>, Original, Skip, Acc, Stack, Decode, Value) when ?is_ws(Byte) ->
@@ -1371,7 +1366,7 @@ array_push(<<"]", Rest/bits>>, Original, Skip, Acc0, Stack0, Decode, Value) ->
13711366
undefined -> [Value | Acc0];
13721367
Push -> Push(Value, Acc0)
13731368
end,
1374-
[_, OldAcc | Stack] = Stack0,
1369+
[OldAcc | Stack] = Stack0,
13751370
{ArrayValue, NewAcc} =
13761371
case Decode#decode.array_finish of
13771372
undefined -> {lists:reverse(Acc), OldAcc};
@@ -1387,7 +1382,6 @@ array_push(<<$,, Rest/bits>>, Original, Skip0, Acc, Stack, Decode, Value) ->
13871382
array_push(_, Original, Skip, Acc, Stack, Decode, Value) ->
13881383
unexpected(Original, Skip, Acc, Stack, Decode, 0, 0, {?FUNCTION_NAME, Value}).
13891384

1390-
13911385
object_start(<<Byte, Rest/bits>>, Original, Skip, Acc, Stack, Decode, Len) when ?is_ws(Byte) ->
13921386
object_start(Rest, Original, Skip, Acc, Stack, Decode, Len+1);
13931387
object_start(<<"}", Rest/bits>>, Original, Skip, Acc, Stack, Decode, Len) ->
@@ -1400,7 +1394,7 @@ object_start(<<"}", Rest/bits>>, Original, Skip, Acc, Stack, Decode, Len) ->
14001394
end,
14011395
continue(Rest, Original, Skip+Len+1, NewAcc, Stack, Decode, Value);
14021396
object_start(<<$", Rest/bits>>, Original, Skip0, OldAcc, Stack0, Decode, Len) ->
1403-
Stack = [?OBJECT, OldAcc | Stack0],
1397+
Stack = {OldAcc, Stack0},
14041398
Skip = Skip0 + Len + 1,
14051399
case Decode#decode.object_start of
14061400
undefined ->
@@ -1427,7 +1421,7 @@ object_push(<<"}", Rest/bits>>, Original, Skip, Acc0, Stack0, Decode, Value, Key
14271421
undefined -> [{Key, Value} | Acc0];
14281422
Fun -> Fun(Key, Value, Acc0)
14291423
end,
1430-
[_, OldAcc | Stack] = Stack0,
1424+
{OldAcc, Stack} = Stack0,
14311425
{ObjectValue, NewAcc} =
14321426
case Decode#decode.object_finish of
14331427
undefined -> {maps:from_list(Acc), OldAcc};
@@ -1452,9 +1446,11 @@ object_key(_, Original, Skip, Acc, Stack, Decode) ->
14521446
continue(<<Rest/bits>>, Original, Skip, Acc, Stack0, Decode, Value) ->
14531447
case Stack0 of
14541448
[] -> terminate(Rest, Original, Skip, Acc, Value);
1455-
[?ARRAY | _] -> array_push(Rest, Original, Skip, Acc, Stack0, Decode, Value);
1456-
[?OBJECT | _] -> object_value(Rest, Original, Skip, Acc, Stack0, Decode, Value);
1457-
[Key | Stack] -> object_push(Rest, Original, Skip, Acc, Stack, Decode, Value, Key)
1449+
[_ | Stack] when is_list(Stack) ->
1450+
array_push(Rest, Original, Skip, Acc, Stack0, Decode, Value);
1451+
[Key | Stack] ->
1452+
object_push(Rest, Original, Skip, Acc, Stack, Decode, Value, Key);
1453+
{_, _} -> object_value(Rest, Original, Skip, Acc, Stack0, Decode, Value)
14581454
end.
14591455

14601456
terminate(<<Byte, Rest/bits>>, Original, Skip, Acc, Value) when ?is_ws(Byte) ->

0 commit comments

Comments
 (0)