comparison Implab/JSON/JSONWriter.cs @ 150:3258399cba83 v2

JSONWriter improvements
author cin
date Sat, 12 Dec 2015 22:12:44 +0300
parents 2100965eb97f
children
comparison
equal deleted inserted replaced
149:eb793fbbe4ea 150:3258399cba83
1 using System; 1 using System;
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 {
8 struct Context { 9 struct Context {
9 public bool needComma; 10 public bool needComma;
10 public JSONElementContext element; 11 public JSONElementContext element;
11 } 12 }
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;
18 21 readonly char[] m_buffer = new char[BUFFER_SIZE];
22 int m_bufferPos;
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,
22 _escapeNL, 28 _escapeNL,
23 _escapeTAB, 29 _escapeTAB,
209 } 215 }
210 216
211 void Write(bool value) { 217 void Write(bool value) {
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) {
218 m_writer.Write("null"); 230 m_writer.Write("null");
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 m_writer.Write(_escapeBKS); 247 escapeSeq = _escapeBKS;
232 break; 248 break;
233 case '\f': 249 case '\f':
234 m_writer.Write(_escapeFWD); 250 escapeSeq = _escapeFWD;
235 break; 251 break;
236 case '\r': 252 case '\r':
237 m_writer.Write(_escapeCR); 253 escapeSeq = _escapeCR;
238 break; 254 break;
239 case '\n': 255 case '\n':
240 m_writer.Write(_escapeNL); 256 escapeSeq = _escapeNL;
241 break; 257 break;
242 case '\t': 258 case '\t':
243 m_writer.Write(_escapeTAB); 259 escapeSeq = _escapeTAB;
244 break; 260 break;
245 case '\\': 261 case '\\':
246 m_writer.Write(_escapeBSLASH); 262 escapeSeq = _escapeBSLASH;
247 break; 263 break;
248 case '"': 264 case '"':
249 m_writer.Write(_escapeQ); 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 m_writer.Write(ch); 280 if (m_bufferPos >= BUFFER_SIZE)
281 FlushBuffer();
282 m_buffer[m_bufferPos++] = ch;
256 } 283 }
257 break; 284 continue;
258 } 285 }
259 } 286
260 287 if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
261 m_writer.Write('"'); 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) {
265 if (double.IsNaN(value)) 304 if (double.IsNaN(value))
266 Write("NaN"); 305 Write("NaN");