aboutsummaryrefslogtreecommitdiffstats
path: root/main/lua-cjson/0004-Option-for-sorting-object-keys.patch
blob: 21c6aae17fe0ff4113aee9db3fa506c16e61ddf6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
From 58da501ed46ee364b10bf079df78e63c195ecd0f Mon Sep 17 00:00:00 2001
From: Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>
Date: Mon, 22 May 2017 19:10:58 +0300
Subject: [PATCH] Option for sorting object keys

---
 lua_cjson.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 62 insertions(+), 6 deletions(-)

diff --git a/lua_cjson.c b/lua_cjson.c
index 22f33f1..ac9fa42 100644
--- a/lua_cjson.c
+++ b/lua_cjson.c
@@ -65,6 +65,10 @@
 #define isinf(x) (!isnan(x) && isnan((x) - (x)))
 #endif
 
+#if LUA_VERSION_NUM > 501
+#define lua_lessthan(l, a, b) (lua_compare((l), (a), (b), LUA_OPLT))
+#endif
+
 #define DEFAULT_SPARSE_CONVERT 0
 #define DEFAULT_SPARSE_RATIO 2
 #define DEFAULT_SPARSE_SAFE 10
@@ -74,6 +78,7 @@
 #define DEFAULT_DECODE_INVALID_NUMBERS 1
 #define DEFAULT_ENCODE_KEEP_BUFFER 1
 #define DEFAULT_ENCODE_NUMBER_PRECISION 14
+#define DEFAULT_ENCODE_SORT_KEYS 0
 
 #ifdef DISABLE_INVALID_NUMBERS
 #undef DEFAULT_DECODE_INVALID_NUMBERS
@@ -130,6 +135,7 @@ typedef struct {
     int encode_invalid_numbers;     /* 2 => Encode as "null" */
     int encode_number_precision;
     int encode_keep_buffer;
+    int encode_sort_keys;
 
     int decode_invalid_numbers;
     int decode_max_depth;
@@ -327,6 +333,14 @@ static int json_cfg_encode_keep_buffer(lua_State *l)
     return 1;
 }
 
+/* Configures whether object keys are sorted when encoding */
+static int json_cfg_encode_sort_keys(lua_State *l)
+{
+    json_config_t *cfg = json_arg_init(l, 1);
+
+    return json_enum_option(l, 1, &cfg->encode_sort_keys, NULL, 1);
+}
+
 #if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)
 void json_verify_invalid_number_setting(lua_State *l, int *setting)
 {
@@ -396,6 +410,7 @@ static void json_create_config(lua_State *l)
     cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS;
     cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;
     cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
+    cfg->encode_sort_keys = DEFAULT_ENCODE_SORT_KEYS;
 
 #if DEFAULT_ENCODE_KEEP_BUFFER > 0
     strbuf_init(&cfg->encode_buf, 0);
@@ -627,24 +642,66 @@ static void json_append_number(lua_State *l, json_config_t *cfg,
     strbuf_extend_length(json, len);
 }
 
+static void sort_lua_stack(lua_State *l, int lo, int hi)
+{
+    if (lo >= hi)
+        return;
+
+    int i = lo - 1;
+    int j = hi + 1;
+
+    lua_pushvalue(l, lo);
+
+    while (1) {
+        while (lua_lessthan(l, -1, ++i));
+        while (lua_lessthan(l, --j, -1));
+        if (i >= j)
+            break;
+
+        lua_pushvalue(l, i);
+        lua_pushvalue(l, j);
+        lua_replace(l, i);
+        lua_replace(l, j);
+    }
+
+    lua_pop(l, 1);
+
+    sort_lua_stack(l, lo, j);
+    sort_lua_stack(l, j + 1, hi);
+}
+
 static void json_append_object(lua_State *l, json_config_t *cfg,
                                int current_depth, strbuf_t *json)
 {
     int comma, keytype;
+    int sort = cfg->encode_sort_keys;
+    int tbl_index = lua_gettop(l);
 
     /* Object */
     strbuf_append_char(json, '{');
 
     lua_pushnil(l);
-    /* table, startkey */
+
+    if (sort) {
+        while (lua_next(l, tbl_index)) {
+            lua_pop(l, 1);
+            lua_pushvalue(l, -1);
+        }
+        sort_lua_stack(l, tbl_index + 1, lua_gettop(l));
+    }
+
     comma = 0;
-    while (lua_next(l, -2) != 0) {
+    while (sort ? lua_gettop(l) > tbl_index : lua_next(l, tbl_index)) {
         if (comma)
             strbuf_append_char(json, ',');
         else
             comma = 1;
 
-        /* table, key, value */
+        if (sort) {
+            lua_pushvalue(l, -1);
+            lua_gettable(l, tbl_index);
+        }
+
         keytype = lua_type(l, -2);
         if (keytype == LUA_TNUMBER) {
             strbuf_append_char(json, '"');
@@ -659,10 +716,8 @@ static void json_append_object(lua_State *l, json_config_t *cfg,
             /* never returns */
         }
 
-        /* table, key, value */
         json_append_data(l, cfg, current_depth, json);
-        lua_pop(l, 1);
-        /* table, key */
+        lua_pop(l, sort ? 2 : 1);
     }
 
     strbuf_append_char(json, '}');
@@ -1365,6 +1420,7 @@ static int lua_cjson_new(lua_State *l)
         { "encode_keep_buffer", json_cfg_encode_keep_buffer },
         { "encode_invalid_numbers", json_cfg_encode_invalid_numbers },
         { "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
+        { "encode_sort_keys", json_cfg_encode_sort_keys },
         { "new", lua_cjson_new },
         { NULL, NULL }
     };
-- 
2.13.0