Browse Source

文字列デコード用のバッファを持ちまわすようにして、文字列が多いJSONのデコード処理効率を向上させた

Takeru Ohta 11 years ago
parent
commit
d9058ec9a8
3 changed files with 135 additions and 132 deletions
  1. 2 1
      README.md
  2. 1 1
      src/jsone.app.src
  3. 132 130
      src/jsone_decode.erl

+ 2 - 1
README.md

@@ -1,4 +1,4 @@
-jsone (0.1.0)
+jsone (0.1.1)
 =============
 
 Erlangで実装されたJSONのエンコード/デコードライブラリ。
@@ -11,6 +11,7 @@ Erlangで実装されたJSONのエンコード/デコードライブラリ。
 - Pure Erlang
 - デコード処理部を実験的にCPS的に実装
   - パース途中にサブバイナリが生成されることを極力抑制して最適化
+  - NIFを使わない実装の中ではおそらく最速
 
 ビルド方法
 ----------

+ 1 - 1
src/jsone.app.src

@@ -2,7 +2,7 @@
 {application, jsone,
  [
   {description, "Erlang JSON Library"},
-  {vsn, "0.1.0"},
+  {vsn, "0.1.1"},
   {registered, []},
   {applications, [
                   kernel,

+ 132 - 130
src/jsone_decode.erl

@@ -27,6 +27,8 @@
 %%%---------------------------------------------------------------------------------------
 -module(jsone_decode).
 
+-compile(inline).
+
 %%--------------------------------------------------------------------------------
 %% Exported API
 %%--------------------------------------------------------------------------------
@@ -57,91 +59,91 @@
 %% デコードに失敗した場合は`{invalid_json, 失敗位置より後のJSON::binary()}'形式のエラーが送出される.
 -spec decode(binary()) -> {jsone:json_value(), RestJson::binary()}.
 decode(<<Json/binary>>) ->
-    whitespace(Json, value, []).
+    whitespace(Json, value, [], <<"">>).
 
 %%--------------------------------------------------------------------------------
 %% Internal Functions
 %%--------------------------------------------------------------------------------
--spec next(binary(), jsone:json_value(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-next(<<Bin/binary>>, Value, []) ->
+-spec next(binary(), jsone:json_value(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+next(<<Bin/binary>>, Value, [], _Buf) ->
     {Value, Bin};
-next(<<Bin/binary>>, Value, [Next | Nexts]) ->
+next(<<Bin/binary>>, Value, [Next | Nexts], Buf) ->
     case Next of
-        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts);
-        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts);
-        {object_next, Key, Members} -> whitespace(Bin, {object_next, Key, Value, Members}, Nexts)
+        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf);
+        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts, Buf);
+        {object_next, Key, Members} -> whitespace(Bin, {object_next, Key, Value, Members}, Nexts, Buf)
     end.
 
--spec whitespace(binary(), whitespace_next(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-whitespace(<<$  , Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
-whitespace(<<$\t, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
-whitespace(<<$\r, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
-whitespace(<<$\n, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
-whitespace(<<Bin/binary>>,      Next, Nexts) ->
+-spec whitespace(binary(), whitespace_next(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+whitespace(<<$  , Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
+whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
+whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
+whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
+whitespace(<<Bin/binary>>,      Next, Nexts, Buf) ->
     case Next of
-        value  -> value(Bin, Nexts);
-        array  -> array(Bin, Nexts);
-        object -> object(Bin, Nexts);
+        value  -> value(Bin, Nexts, Buf);
+        array  -> array(Bin, Nexts, Buf);
+        object -> object(Bin, Nexts, Buf);
         string -> case Bin of
-                      <<$", Bin2/binary>> -> string(Bin2, [], Nexts);
+                      <<$", Bin2/binary>> -> string(Bin2, byte_size(Buf), Nexts, Buf);
                       _                   -> ?ERROR(Bin)
                   end;
-        {array_next, Values}               -> array_next(Bin, Values, Nexts);
-        {object_value, Key, Members}       -> object_value(Bin, Key, Members, Nexts);
-        {object_next, Key, Value, Members} -> object_next(Bin, [{Key, Value} | Members], Nexts)
+        {array_next, Values}               -> array_next(Bin, Values, Nexts, Buf);
+        {object_value, Key, Members}       -> object_value(Bin, Key, Members, Nexts, Buf);
+        {object_next, Key, Value, Members} -> object_next(Bin, [{Key, Value} | Members], Nexts, Buf)
     end.
 
--spec value(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-value(<<"false", Bin/binary>>, Nexts) -> next(Bin, false, Nexts);
-value(<<"true", Bin/binary>>, Nexts)  -> next(Bin, true, Nexts);
-value(<<"null", Bin/binary>>, Nexts)  -> next(Bin, null, Nexts);
-value(<<$[, Bin/binary>>, Nexts)      -> whitespace(Bin, array, Nexts);
-value(<<${, Bin/binary>>, Nexts)      -> whitespace(Bin, object, Nexts);
-value(<<$", Bin/binary>>, Nexts)      -> string(Bin, [], Nexts);
-value(<<Bin/binary>>, Nexts)          -> number(Bin, Nexts).
-
--spec array(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-array(<<$], Bin/binary>>, Nexts) -> next(Bin, [], Nexts);
-array(<<Bin/binary>>, Nexts)     -> whitespace(Bin, value, [{array_next, []} | Nexts]).
-
--spec array_next(binary(), [jsone:json_value()], [next()]) -> {jsone:json_value(), Rest::binary()}.
-array_next(<<$], Bin/binary>>, Values, Nexts) -> next(Bin, lists:reverse(Values), Nexts);
-array_next(<<$,, Bin/binary>>, Values, Nexts) -> whitespace(Bin, value, [{array_next, Values} | Nexts]);
-array_next(<<Bin/binary>>, _Values, _Nexts)   -> ?ERROR(Bin).
-
--spec object(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-object(<<$}, Bin/binary>>, Nexts) -> next(Bin, {object, []}, Nexts);
-object(<<Bin/binary>>, Nexts) -> whitespace(Bin, string, [{object_value, []} | Nexts]).
-
--spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-object_value(<<$:, Bin/binary>>, Key, Members, Nexts) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts]);
-object_value(<<Bin/binary>>, _Key, _Members, _Nexts)  -> ?ERROR(Bin).
-
--spec object_next(binary(), jsone:json_object_members(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-object_next(<<$}, Bin/binary>>, Members, Nexts) -> next(Bin, {object, lists:reverse(Members)}, Nexts);
-object_next(<<$,, Bin/binary>>, Members, Nexts) -> whitespace(Bin, string, [{object_value, Members} | Nexts]);
-object_next(<<Bin/binary>>, _Members, _Nexts)   -> ?ERROR(Bin).
-
--spec string(binary(), iolist(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-string(<<$", Bin/binary>>, Acc, Nexts) -> next(Bin, list_to_binary(lists:reverse(Acc)), Nexts);
-string(<<$\\, B/binary>>,  Acc, Nexts) ->
+-spec value(binary(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+value(<<"false", Bin/binary>>, Nexts, Buf) -> next(Bin, false, Nexts, Buf);
+value(<<"true", Bin/binary>>, Nexts, Buf)  -> next(Bin, true, Nexts, Buf);
+value(<<"null", Bin/binary>>, Nexts, Buf)  -> next(Bin, null, Nexts, Buf);
+value(<<$[, Bin/binary>>, Nexts, Buf)      -> whitespace(Bin, array, Nexts, Buf);
+value(<<${, Bin/binary>>, Nexts, Buf)      -> whitespace(Bin, object, Nexts, Buf);
+value(<<$", Bin/binary>>, Nexts, Buf)      -> string(Bin, byte_size(Buf), Nexts, Buf);
+value(<<Bin/binary>>, Nexts, Buf)          -> number(Bin, Nexts, Buf).
+
+-spec array(binary(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+array(<<$], Bin/binary>>, Nexts, Buf) -> next(Bin, [], Nexts, Buf);
+array(<<Bin/binary>>, Nexts, Buf)     -> whitespace(Bin, value, [{array_next, []} | Nexts], Buf).
+
+-spec array_next(binary(), [jsone:json_value()], [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+array_next(<<$], Bin/binary>>, Values, Nexts, Buf) -> next(Bin, lists:reverse(Values), Nexts, Buf);
+array_next(<<$,, Bin/binary>>, Values, Nexts, Buf) -> whitespace(Bin, value, [{array_next, Values} | Nexts], Buf);
+array_next(<<Bin/binary>>, _Values, _Nexts, _Buf)  -> ?ERROR(Bin).
+
+-spec object(binary(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+object(<<$}, Bin/binary>>, Nexts, Buf) -> next(Bin, {object, []}, Nexts, Buf);
+object(<<Bin/binary>>, Nexts, Buf) -> whitespace(Bin, string, [{object_value, []} | Nexts], Buf).
+
+-spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+object_value(<<$:, Bin/binary>>, Key, Members, Nexts, Buf) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts], Buf);
+object_value(<<Bin/binary>>, _Key, _Members, _Nexts, _Buf) -> ?ERROR(Bin).
+
+-spec object_next(binary(), jsone:json_object_members(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+object_next(<<$}, Bin/binary>>, Members, Nexts, Buf) -> next(Bin, {object, lists:reverse(Members)}, Nexts, Buf);
+object_next(<<$,, Bin/binary>>, Members, Nexts, Buf) -> whitespace(Bin, string, [{object_value, Members} | Nexts], Buf);
+object_next(<<Bin/binary>>, _Members, _Nexts, _Buf)  -> ?ERROR(Bin).
+
+-spec string(binary(), non_neg_integer(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+string(<<$", Bin/binary>>, Start, Nexts, Buf) -> next(Bin, binary:part(Buf, Start, byte_size(Buf) - Start), Nexts, Buf);
+string(<<$\\, B/binary>>,  Start, Nexts, Buf) ->
     case B of
-        <<$", Bin/binary>> -> string(Bin, [$" | Acc], Nexts);
-        <<$/, Bin/binary>> -> string(Bin, [$/ | Acc], Nexts);
-        <<$\\,Bin/binary>> -> string(Bin, [$\\| Acc], Nexts);
-        <<$b, Bin/binary>> -> string(Bin, [$\b | Acc], Nexts);
-        <<$f, Bin/binary>> -> string(Bin, [$\f | Acc], Nexts);
-        <<$n, Bin/binary>> -> string(Bin, [$\n | Acc], Nexts);
-        <<$r, Bin/binary>> -> string(Bin, [$\r | Acc], Nexts);
-        <<$t, Bin/binary>> -> string(Bin, [$\t | Acc], Nexts);
-        <<$u, Bin/binary>> -> unicode_string(Bin, Acc, Nexts);
+        <<$", Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $">>);
+        <<$/, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $/>>);
+        <<$\\,Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\\>>);
+        <<$b, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\b>>);
+        <<$f, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\f>>);
+        <<$n, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\n>>);
+        <<$r, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\r>>);
+        <<$t, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, $\t>>);
+        <<$u, Bin/binary>> -> unicode_string(Bin, Start, Nexts, Buf);
         _                  -> ?ERROR(B)
     end;
-string(<<C, Bin/binary>>, Acc, Nexts) when 16#20 =< C ->
-    string(Bin, [C | Acc], Nexts).
+string(<<C, Bin/binary>>, Start, Nexts, Buf) when 16#20 =< C ->
+    string(Bin, Start, Nexts, <<Buf/binary, C>>).
 
--spec unicode_string(binary(), iolist(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-unicode_string(<<N:4/binary, Bin/binary>>, Acc, Nexts) ->
+-spec unicode_string(binary(), non_neg_integer(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf) ->
     case binary_to_integer(N, 16) of
         High when 16#D800 =< High, High =< 16#DBFF ->
             %% サロゲートペア
@@ -150,7 +152,7 @@ unicode_string(<<N:4/binary, Bin/binary>>, Acc, Nexts) ->
                     case binary_to_integer(N2, 16) of
                         Low when 16#DC00 =< Low, Low =< 16#DFFF ->
                             Unicode = 16#10000 + (High - 16#D800) * 16#400 + (Low - 16#DC00),
-                            string(Bin2, unicode_to_utf8(Unicode, Acc), Nexts);
+                            string(Bin2, Start, Nexts, unicode_to_utf8(Unicode, Buf));
                         _ -> ?ERROR(Bin)
                     end;
                 _ -> ?ERROR(Bin)
@@ -158,86 +160,86 @@ unicode_string(<<N:4/binary, Bin/binary>>, Acc, Nexts) ->
         Unicode when 16#DC00 =< Unicode, Unicode =< 16#DFFF ->  % サロゲートペアの後半部分
             ?ERROR(<<N/binary, Bin/binary>>);
         Unicode -> 
-            string(Bin, unicode_to_utf8(Unicode, Acc), Nexts)
+            string(Bin, Start, Nexts, unicode_to_utf8(Unicode, Buf))
     end;
-unicode_string(<<Bin/binary>>, _Acc, _Nexts) ->
+unicode_string(<<Bin/binary>>, _Acc, _Nexts, _Buf) ->
     ?ERROR(Bin).
 
--spec unicode_to_utf8(0..1114111, iolist()) -> iolist().
-unicode_to_utf8(Code, Acc) when Code < 16#80 ->
-    [Code | Acc];
-unicode_to_utf8(Code, Acc) when Code < 16#800 ->
+-spec unicode_to_utf8(0..1114111, binary()) -> iolist().
+unicode_to_utf8(Code, Buf) when Code < 16#80 ->
+    <<Buf/binary, Code>>;
+unicode_to_utf8(Code, Buf) when Code < 16#800 ->
     A = 2#11000000 bor (Code bsr 6),
     B = 2#10000000 bor (Code band 2#111111),
-    [B, A | Acc];
-unicode_to_utf8(Code, Acc) when Code < 16#10000 ->
+    <<Buf/binary, A, B>>;
+unicode_to_utf8(Code, Buf) when Code < 16#10000 ->
     A = 2#11100000 bor (Code bsr 12),
     B = 2#10000000 bor ((Code bsr 6) band 2#111111),
     C = 2#10000000 bor (Code band 2#111111),
-    [C, B, A | Acc];
-unicode_to_utf8(Code, Acc) -> % NOTE: サロゲートペアの仕組み上、コード値が上限を越えることはないので、ここでの範囲チェックは不要
+    <<Buf/binary, A, B, C>>;
+unicode_to_utf8(Code, Buf) -> % NOTE: サロゲートペアの仕組み上、コード値が上限を越えることはないので、ここでの範囲チェックは不要
     A = 2#11110000 bor (Code bsr 18),
     B = 2#10000000 bor ((Code bsr 12) band 2#111111),
     C = 2#10000000 bor ((Code bsr  6) band 2#111111),
     D = 2#10000000 bor (Code band 2#111111),
-    [D, C, B, A | Acc].
-
--spec number(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-number(<<$-, Bin/binary>>, Nexts) -> number_integer_part(Bin, -1, Nexts);
-number(<<Bin/binary>>,     Nexts) -> number_integer_part(Bin,  1, Nexts).
-
--spec number_integer_part(binary(), 1|-1, [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_integer_part(<<$0, Bin/binary>>, Sign, Nexts) ->
-    number_fraction_part(Bin, Sign, 0, Nexts);
-number_integer_part(<<C, Bin/binary>>, Sign, Nexts) when $1 =< C, C =< $9 ->
-    number_integer_part_rest(Bin, C - $0, Sign, Nexts);
-number_integer_part(<<Bin/binary>>, _Sign, _Nexts) ->
+    <<Buf/binary, A, B, C, D>>.
+
+-spec number(binary(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number(<<$-, Bin/binary>>, Nexts, Buf) -> number_integer_part(Bin, -1, Nexts, Buf);
+number(<<Bin/binary>>,     Nexts, Buf) -> number_integer_part(Bin,  1, Nexts, Buf).
+
+-spec number_integer_part(binary(), 1|-1, [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_integer_part(<<$0, Bin/binary>>, Sign, Nexts, Buf) ->
+    number_fraction_part(Bin, Sign, 0, Nexts, Buf);
+number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf) when $1 =< C, C =< $9 ->
+    number_integer_part_rest(Bin, C - $0, Sign, Nexts, Buf);
+number_integer_part(<<Bin/binary>>, _Sign, _Nexts, _Buf) ->
     ?ERROR(Bin).
 
--spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts) when $0 =< C, C =< $9 ->
-    number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts);
-number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts) ->
-    number_fraction_part(Bin, Sign, N, Nexts).
-
--spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts) ->
-    number_fraction_part_rest(Bin, Sign, Int, 0, Nexts);
-number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts) ->
-    number_exponation_part(Bin, Sign * Int, 0, Nexts).
-
--spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts) when $0 =< C, C =< $9 ->
-    number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts);
-number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts) when DecimalOffset > 0 ->
-    number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts);
-number_fraction_part_rest(<<Bin/binary>>, _Sign, _N, _DecimalOffset, _Nexts) ->
+-spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts, Buf) when $0 =< C, C =< $9 ->
+    number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts, Buf);
+number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts, Buf) ->
+    number_fraction_part(Bin, Sign, N, Nexts, Buf).
+
+-spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts, Buf) ->
+    number_fraction_part_rest(Bin, Sign, Int, 0, Nexts, Buf);
+number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts, Buf) ->
+    number_exponation_part(Bin, Sign * Int, 0, Nexts, Buf).
+
+-spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf) when $0 =< C, C =< $9 ->
+    number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts, Buf);
+number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf) when DecimalOffset > 0 ->
+    number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts, Buf);
+number_fraction_part_rest(<<Bin/binary>>, _Sign, _N, _DecimalOffset, _Nexts, _Buf) ->
     ?ERROR(Bin).
 
--spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
-number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
-number_exponation_part(<<$e, $-, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts);
-number_exponation_part(<<$E, $-, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts);
-number_exponation_part(<<$e, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
-number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
-number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts) ->
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
+number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
+number_exponation_part(<<$e, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf);
+number_exponation_part(<<$E, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf);
+number_exponation_part(<<$e, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
+number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
+number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
     case DecimalOffset of
-        0 -> next(Bin, N, Nexts);
-        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts)
+        0 -> next(Bin, N, Nexts, Buf);
+        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf)
     end.
 
--spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()]) -> {jsone:json_value(), Rest::binary()}.
-number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts) when $0 =< C, C =< $9 ->
-    number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts);
-number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts) ->
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()], binary()) -> {jsone:json_value(), Rest::binary()}.
+number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts, Buf) when $0 =< C, C =< $9 ->
+    number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts, Buf);
+number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf) ->
     Pos = ExpSign * Exp - DecimalOffset,
-    next(Bin, N * math:pow(10, Pos), Nexts);
-number_exponation_part(<<Bin/binary>>, _N, _DecimalOffset, _ExpSign, _Exp, _IsFirst, _Nexts) ->
+    next(Bin, N * math:pow(10, Pos), Nexts, Buf);
+number_exponation_part(<<Bin/binary>>, _N, _DecimalOffset, _ExpSign, _Exp, _IsFirst, _Nexts, _Buf) ->
     ?ERROR(Bin).