@@ -2,6 +2,7 | |||||
2 | using System.Collections.Generic; |
|
2 | using System.Collections.Generic; | |
3 | using System.IO; |
|
3 | using System.IO; | |
4 | using System.Globalization; |
|
4 | using System.Globalization; | |
|
5 | using System.Diagnostics; | |||
5 |
|
6 | |||
6 | namespace Implab.JSON { |
|
7 | namespace Implab.JSON { | |
7 | public class JSONWriter { |
|
8 | public class JSONWriter { | |
@@ -12,10 +13,15 namespace Implab.JSON { | |||||
12 | Stack<Context> m_contextStack = new Stack<Context>(); |
|
13 | Stack<Context> m_contextStack = new Stack<Context>(); | |
13 | Context m_context; |
|
14 | Context m_context; | |
14 |
|
15 | |||
|
16 | const int BUFFER_SIZE = 64; | |||
|
17 | ||||
15 | TextWriter m_writer; |
|
18 | TextWriter m_writer; | |
16 | readonly bool m_indent = true; |
|
19 | readonly bool m_indent = true; | |
17 | readonly int m_indentSize = 4; |
|
20 | readonly int m_indentSize = 4; | |
|
21 | readonly char[] m_buffer = new char[BUFFER_SIZE]; | |||
|
22 | int m_bufferPos; | |||
18 |
|
23 | |||
|
24 | static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; | |||
19 | static readonly char [] _escapeBKS, |
|
25 | static readonly char [] _escapeBKS, | |
20 | _escapeFWD, |
|
26 | _escapeFWD, | |
21 | _escapeCR, |
|
27 | _escapeCR, | |
@@ -212,6 +218,12 namespace Implab.JSON { | |||||
212 | m_writer.Write(value ? "true" : "false"); |
|
218 | m_writer.Write(value ? "true" : "false"); | |
213 | } |
|
219 | } | |
214 |
|
220 | |||
|
221 | void FlushBuffer() { | |||
|
222 | if (m_bufferPos > 0) { | |||
|
223 | m_writer.Write(m_buffer, 0, m_bufferPos); | |||
|
224 | m_bufferPos = 0; | |||
|
225 | } | |||
|
226 | } | |||
215 |
|
227 | |||
216 | void Write(string value) { |
|
228 | void Write(string value) { | |
217 | if (value == null) { |
|
229 | if (value == null) { | |
@@ -219,46 +231,73 namespace Implab.JSON { | |||||
219 | return; |
|
231 | return; | |
220 | } |
|
232 | } | |
221 |
|
233 | |||
|
234 | Debug.Assert(m_bufferPos == 0); | |||
|
235 | ||||
222 | var chars = value.ToCharArray(); |
|
236 | var chars = value.ToCharArray(); | |
223 | m_writer.Write('"'); |
|
237 | m_buffer[m_bufferPos++] = '"'; | |
224 |
|
238 | |||
225 | // Analysis disable once ForCanBeConvertedToForeach |
|
239 | // Analysis disable once ForCanBeConvertedToForeach | |
226 | for (int i = 0; i < chars.Length; i++) { |
|
240 | for (int i = 0; i < chars.Length; i++) { | |
227 | var ch = chars[i]; |
|
241 | var ch = chars[i]; | |
228 |
|
242 | |||
|
243 | char[] escapeSeq; | |||
|
244 | ||||
229 | switch (ch) { |
|
245 | switch (ch) { | |
230 | case '\b': |
|
246 | case '\b': | |
231 |
|
|
247 | escapeSeq = _escapeBKS; | |
232 | break; |
|
248 | break; | |
233 | case '\f': |
|
249 | case '\f': | |
234 |
|
|
250 | escapeSeq = _escapeFWD; | |
235 | break; |
|
251 | break; | |
236 | case '\r': |
|
252 | case '\r': | |
237 |
|
|
253 | escapeSeq = _escapeCR; | |
238 | break; |
|
254 | break; | |
239 | case '\n': |
|
255 | case '\n': | |
240 |
|
|
256 | escapeSeq = _escapeNL; | |
241 | break; |
|
257 | break; | |
242 | case '\t': |
|
258 | case '\t': | |
243 |
|
|
259 | escapeSeq = _escapeTAB; | |
244 | break; |
|
260 | break; | |
245 | case '\\': |
|
261 | case '\\': | |
246 |
|
|
262 | escapeSeq = _escapeBSLASH; | |
247 | break; |
|
263 | break; | |
248 | case '"': |
|
264 | case '"': | |
249 |
|
|
265 | escapeSeq = _escapeQ; | |
250 | break; |
|
266 | break; | |
251 | default: |
|
267 | default: | |
252 | if (ch < 0x20) { |
|
268 | if (ch < 0x20) { | |
253 | m_writer.Write("\\u00{0:x2}",(int)ch); |
|
269 | if (m_bufferPos + 6 > BUFFER_SIZE) | |
|
270 | FlushBuffer(); | |||
|
271 | ||||
|
272 | m_buffer[m_bufferPos++] = '\\'; | |||
|
273 | m_buffer[m_bufferPos++] = 'u'; | |||
|
274 | m_buffer[m_bufferPos++] = '0'; | |||
|
275 | m_buffer[m_bufferPos++] = '0'; | |||
|
276 | m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf]; | |||
|
277 | m_buffer[m_bufferPos++] = _hex[ch & 0xf]; | |||
|
278 | ||||
254 | } else { |
|
279 | } else { | |
255 |
|
|
280 | if (m_bufferPos >= BUFFER_SIZE) | |
|
281 | FlushBuffer(); | |||
|
282 | m_buffer[m_bufferPos++] = ch; | |||
256 | } |
|
283 | } | |
257 |
|
|
284 | continue; | |
258 | } |
|
|||
259 | } |
|
285 | } | |
260 |
|
286 | |||
261 | m_writer.Write('"'); |
|
287 | if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE) | |
|
288 | FlushBuffer(); | |||
|
289 | ||||
|
290 | Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length); | |||
|
291 | m_bufferPos += escapeSeq.Length; | |||
|
292 | ||||
|
293 | } | |||
|
294 | ||||
|
295 | if (m_bufferPos >= BUFFER_SIZE) | |||
|
296 | FlushBuffer(); | |||
|
297 | ||||
|
298 | m_buffer[m_bufferPos++] = '"'; | |||
|
299 | ||||
|
300 | FlushBuffer(); | |||
262 | } |
|
301 | } | |
263 |
|
302 | |||
264 | void Write(double value) { |
|
303 | void Write(double value) { |
@@ -5,6 +5,8 using Implab; | |||||
5 | using System.Collections.Generic; |
|
5 | using System.Collections.Generic; | |
6 | using System.Collections.Concurrent; |
|
6 | using System.Collections.Concurrent; | |
7 | using System.Threading; |
|
7 | using System.Threading; | |
|
8 | using Implab.JSON; | |||
|
9 | using System.IO; | |||
8 |
|
10 | |||
9 | namespace MonoPlay { |
|
11 | namespace MonoPlay { | |
10 | class MainClass { |
|
12 | class MainClass { | |
@@ -16,25 +18,27 namespace MonoPlay { | |||||
16 |
|
18 | |||
17 | var t1 = Environment.TickCount; |
|
19 | var t1 = Environment.TickCount; | |
18 |
|
20 | |||
19 |
for |
|
21 | for(int i =0; i < 1000000; i++) | |
|
22 | using (var tw = new StringWriter()) { | |||
|
23 | var jw = new JSONWriter(tw); | |||
20 |
|
24 | |||
21 | var p = new Promise<int>(); |
|
25 | jw.WriteValue("\r\nhere\tvalue\u0002\u0003"); | |
22 | p.On(HandleResult); |
|
26 | ||
23 |
|
|
27 | //Console.WriteLine(tw); | |
24 | } |
|
28 | } | |
25 |
|
29 | |||
|
30 | ||||
|
31 | ||||
26 | var t2 = Environment.TickCount; |
|
32 | var t2 = Environment.TickCount; | |
27 | Console.WriteLine("done: {0} ms, {1:.00} Mb, {2} GC", t2 - t1, GC.GetTotalMemory(false) / (1024*1024), GC.CollectionCount(0) ); |
|
33 | Console.WriteLine("done: {0} ms, {1:.00} Mb, {2} GC", t2 - t1, GC.GetTotalMemory(false) / (1024*1024), GC.CollectionCount(0) ); | |
28 |
|
34 | |||
29 | } |
|
35 | } | |
30 |
|
36 | |||
31 |
static void |
|
37 | static void DoTest() { | |
32 | { |
|
38 | ||
|
39 | ||||
33 |
|
40 | |||
34 | } |
|
41 | } | |
35 |
|
42 | |||
36 | static void HandleResult(int x) { |
|
|||
37 |
|
||||
38 |
|
|
43 | } | |
39 | } |
|
44 | } | |
40 | } |
|
General Comments 0
You need to be logged in to leave comments.
Login now