##// END OF EJS Templates
Reimplemented JsonXmlReader, added support for null values: JSON null values are...
cin -
r227:8d5de4eb9c2c v2
parent child
Show More
This diff has been collapsed as it changes many lines, (629 lines changed) Show them Hide them
@@ -0,0 +1,629
1 using Implab.Formats.JSON;
2 using System;
3 using System.Collections.Generic;
4 using System.Globalization;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 using System.Xml;
9
10 namespace Implab.Xml {
11 public class JsonXmlReader : XmlReader {
12 struct JsonContext {
13 public string localName;
14 public bool skip;
15 }
16
17 JSONParser m_parser;
18 JsonXmlReaderOptions m_options;
19 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
20 XmlNameTable m_nameTable;
21
22 readonly string m_jsonRootName;
23 readonly string m_jsonNamespace;
24 readonly string m_jsonPrefix;
25 readonly bool m_jsonFlattenArrays;
26 readonly string m_jsonArrayItemName;
27
28 string m_jsonLocalName;
29 string m_jsonValueName;
30 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
31
32 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
33
34 XmlQualifiedName m_elementQName;
35 string m_elementPrefix;
36 int m_elementDepth;
37 bool m_elementIsEmpty;
38
39 XmlQualifiedName m_qName;
40 string m_prefix;
41 int m_xmlDepth;
42
43 XmlSimpleAttribute[] m_attributes;
44 object m_value;
45 bool m_isEmpty;
46
47 XmlNodeType m_nodeType = XmlNodeType.None;
48
49 bool m_isAttribute; // indicates that we are reading attribute nodes
50 int m_currentAttribute;
51 bool m_currentAttributeRead;
52
53
54 XmlNameContext m_context;
55 int m_nextPrefix = 1;
56
57 readonly string m_xmlnsPrefix;
58 readonly string m_xmlnsNamespace;
59 readonly string m_xsiPrefix;
60 readonly string m_xsiNamespace;
61
62
63 public JsonXmlReader(JSONParser parser, JsonXmlReaderOptions options) {
64 Safe.ArgumentNotNull(parser, nameof(parser));
65 m_parser = parser;
66
67 m_options = options ?? new JsonXmlReaderOptions();
68
69 m_jsonFlattenArrays = m_options.FlattenArrays;
70 m_nameTable = m_options.NameTable ?? new NameTable();
71
72 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
73 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
74 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
75 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
76 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
77 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
78 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
79 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
80
81 // TODO validate m_jsonRootName, m_jsonArrayItemName
82
83 m_context = new XmlNameContext(null);
84 }
85
86 public override int AttributeCount {
87 get {
88 return m_attributes == null ? 0 : m_attributes.Length;
89 }
90 }
91
92 public override string BaseURI {
93 get {
94 return string.Empty;
95 }
96 }
97
98 public override int Depth {
99 get {
100 return m_xmlDepth;
101 }
102 }
103
104 public override bool EOF {
105 get {
106 return m_position == JsonXmlReaderPosition.Eof;
107 }
108 }
109
110 public override bool IsEmptyElement {
111 get { return m_isEmpty; }
112 }
113
114
115 public override string LocalName {
116 get {
117 return m_qName.Name;
118 }
119 }
120
121 public override string NamespaceURI {
122 get {
123 return m_qName.Namespace;
124 }
125 }
126
127 public override XmlNameTable NameTable {
128 get {
129 return m_nameTable;
130 }
131 }
132
133 public override XmlNodeType NodeType {
134 get {
135 return m_nodeType;
136 }
137 }
138
139 public override string Prefix {
140 get {
141 return m_prefix;
142 }
143 }
144
145 public override ReadState ReadState {
146 get {
147 switch (m_position) {
148 case JsonXmlReaderPosition.Initial:
149 return ReadState.Initial;
150 case JsonXmlReaderPosition.Eof:
151 return ReadState.EndOfFile;
152 case JsonXmlReaderPosition.Closed:
153 return ReadState.Closed;
154 case JsonXmlReaderPosition.Error:
155 return ReadState.Error;
156 default:
157 return ReadState.Interactive;
158 };
159 }
160 }
161
162 public override string Value {
163 get {
164 return ConvertValueToString(m_value);
165 }
166 }
167
168 static string ConvertValueToString(object value) {
169 if (value == null)
170 return string.Empty;
171
172 switch (Convert.GetTypeCode(value)) {
173 case TypeCode.Double:
174 return ((double)value).ToString(CultureInfo.InvariantCulture);
175 case TypeCode.String:
176 return (string)value;
177 case TypeCode.Boolean:
178 return (bool)value ? "true" : "false";
179 default:
180 return value.ToString();
181 }
182 }
183
184 public override string GetAttribute(int i) {
185 Safe.ArgumentInRange(i, 0, AttributeCount - 1, nameof(i));
186 return ConvertValueToString(m_attributes[i].Value);
187 }
188
189 public override string GetAttribute(string name) {
190 if (m_attributes == null)
191 return null;
192 var qName = m_context.Resolve(name);
193 var attr = Array.Find(m_attributes, x => x.QName == qName);
194 var value = ConvertValueToString(attr?.Value);
195 return value == string.Empty ? null : value;
196 }
197
198 public override string GetAttribute(string name, string namespaceURI) {
199 if (m_attributes == null)
200 return null;
201 var qName = new XmlQualifiedName(name, namespaceURI);
202 var attr = Array.Find(m_attributes, x => x.QName == qName);
203 var value = ConvertValueToString(attr?.Value);
204 return value == string.Empty ? null : value;
205 }
206
207 public override string LookupNamespace(string prefix) {
208 return m_context.ResolvePrefix(prefix);
209 }
210
211 public override bool MoveToAttribute(string name) {
212 if (m_attributes == null || m_attributes.Length == 0)
213 return false;
214
215 var qName = m_context.Resolve(name);
216 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
217 if (index >= 0) {
218 MoveToAttributeImpl(index);
219 return true;
220 }
221 return false;
222 }
223
224 public override bool MoveToAttribute(string name, string ns) {
225 if (m_attributes == null || m_attributes.Length == 0)
226 return false;
227
228 var qName = m_context.Resolve(name);
229 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
230 if (index >= 0) {
231 MoveToAttributeImpl(index);
232 return true;
233 }
234 return false;
235 }
236
237 void MoveToAttributeImpl(int i) {
238 if (!m_isAttribute) {
239 m_elementQName = m_qName;
240 m_elementDepth = m_xmlDepth;
241 m_elementPrefix = m_prefix;
242 m_elementIsEmpty = m_isEmpty;
243 m_isAttribute = true;
244 }
245
246 var attr = m_attributes[i];
247
248
249 m_currentAttribute = i;
250 m_currentAttributeRead = false;
251 m_nodeType = XmlNodeType.Attribute;
252
253 m_xmlDepth = m_elementDepth + 1;
254 m_qName = attr.QName;
255 m_value = attr.Value;
256 m_prefix = attr.Prefix;
257 }
258
259 public override bool MoveToElement() {
260 if (m_isAttribute) {
261 m_value = null;
262 m_nodeType = XmlNodeType.Element;
263 m_xmlDepth = m_elementDepth;
264 m_prefix = m_elementPrefix;
265 m_qName = m_elementQName;
266 m_isEmpty = m_elementIsEmpty;
267 m_isAttribute = false;
268 return true;
269 }
270 return false;
271 }
272
273 public override bool MoveToFirstAttribute() {
274 if (m_attributes != null && m_attributes.Length > 0) {
275 MoveToAttributeImpl(0);
276 return true;
277 }
278 return false;
279 }
280
281 public override bool MoveToNextAttribute() {
282 if (m_isAttribute) {
283 var next = m_currentAttribute + 1;
284 if (next < AttributeCount) {
285 MoveToAttributeImpl(next);
286 return true;
287 }
288 return false;
289 } else {
290 return MoveToFirstAttribute();
291 }
292
293 }
294
295 public override bool ReadAttributeValue() {
296 if (!m_isAttribute || m_currentAttributeRead)
297 return false;
298
299 ValueNode(m_attributes[m_currentAttribute].Value);
300 m_currentAttributeRead = true;
301 return true;
302 }
303
304 public override void ResolveEntity() {
305 /* do nothing */
306 }
307
308 /// <summary>
309 /// Determines do we need to increase depth after the current node
310 /// </summary>
311 /// <returns></returns>
312 public bool IsSibling() {
313 switch (m_nodeType) {
314 case XmlNodeType.None: // start document
315 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
316 return false;
317 case XmlNodeType.Element:
318 // if the elemnt is empty the next element will be it's sibling
319 return m_isEmpty;
320
321 case XmlNodeType.Document:
322 case XmlNodeType.DocumentFragment:
323 case XmlNodeType.Entity:
324 case XmlNodeType.Text:
325 case XmlNodeType.CDATA:
326 case XmlNodeType.EntityReference:
327 case XmlNodeType.ProcessingInstruction:
328 case XmlNodeType.Comment:
329 case XmlNodeType.DocumentType:
330 case XmlNodeType.Notation:
331 case XmlNodeType.Whitespace:
332 case XmlNodeType.SignificantWhitespace:
333 case XmlNodeType.EndElement:
334 case XmlNodeType.EndEntity:
335 case XmlNodeType.XmlDeclaration:
336 default:
337 return true;
338 }
339 }
340
341 void ValueNode(object value) {
342 if (!IsSibling()) // the node is nested
343 m_xmlDepth++;
344
345 m_qName = XmlQualifiedName.Empty;
346 m_nodeType = XmlNodeType.Text;
347 m_prefix = string.Empty;
348 m_value = value;
349 m_isEmpty = false;
350 m_attributes = null;
351 }
352
353 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
354 if (!IsSibling()) // the node is nested
355 m_xmlDepth++;
356
357 m_context = new XmlNameContext(m_context);
358 List<XmlSimpleAttribute> definedAttrs = null;
359
360 // define new namespaces
361 if (attrs != null) {
362 foreach (var attr in attrs) {
363 if (attr.QName.Name == "xmlns") {
364 m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
365 } else if (attr.Prefix == m_xmlnsPrefix) {
366 m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
367 } else {
368 string attrPrefix;
369 if (string.IsNullOrEmpty(attr.QName.Namespace))
370 continue;
371
372 // auto-define prefixes
373 if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
374 // new namespace prefix added
375 attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
376 attr.Prefix = attrPrefix;
377
378 if (definedAttrs == null)
379 definedAttrs = new List<XmlSimpleAttribute>();
380
381 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
382 }
383 }
384 }
385 }
386
387 string p;
388 // auto-define prefixes
389 if (!m_context.LookupNamespacePrefix(ns, out p)) {
390 p = m_context.CreateNamespacePrefix(ns);
391 if (definedAttrs == null)
392 definedAttrs = new List<XmlSimpleAttribute>();
393
394 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
395 }
396
397 if (definedAttrs != null) {
398 if (attrs != null)
399 definedAttrs.AddRange(attrs);
400 attrs = definedAttrs.ToArray();
401 }
402
403 m_nodeType = XmlNodeType.Element;
404 m_qName = new XmlQualifiedName(name, ns);
405 m_prefix = p;
406 m_value = null;
407 m_isEmpty = empty;
408 m_attributes = attrs;
409 }
410
411 void EndElementNode(string name, string ns) {
412 if (IsSibling()) // closing the element which has children
413 m_xmlDepth--;
414
415 string p;
416 if (!m_context.LookupNamespacePrefix(ns, out p))
417 throw new Exception($"Failed to lookup namespace '{ns}'");
418
419 m_context = m_context.ParentContext;
420 m_nodeType = XmlNodeType.EndElement;
421 m_prefix = p;
422 m_qName = new XmlQualifiedName(name, ns);
423 m_value = null;
424 m_attributes = null;
425 m_isEmpty = false;
426 }
427
428 void XmlDeclaration() {
429 if (!IsSibling()) // the node is nested
430 m_xmlDepth++;
431 m_nodeType = XmlNodeType.XmlDeclaration;
432 m_qName = new XmlQualifiedName("xml");
433 m_value = "version='1.0'";
434 m_prefix = string.Empty;
435 m_attributes = null;
436 m_isEmpty = false;
437 }
438
439 public override bool Read() {
440 try {
441 string elementName;
442 XmlSimpleAttribute[] elementAttrs = null;
443 MoveToElement();
444
445 switch (m_position) {
446 case JsonXmlReaderPosition.Initial:
447 m_jsonLocalName = m_jsonRootName;
448 m_jsonSkip = false;
449 XmlDeclaration();
450 m_position = JsonXmlReaderPosition.Declaration;
451 return true;
452 case JsonXmlReaderPosition.Declaration:
453 elementAttrs = new[] {
454 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
455 string.IsNullOrEmpty(m_jsonPrefix) ?
456 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
457 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
458 };
459 break;
460 case JsonXmlReaderPosition.ValueElement:
461 if (!m_isEmpty) {
462 ValueNode(m_parser.ElementValue);
463 m_position = JsonXmlReaderPosition.ValueContent;
464 return true;
465 } else {
466 m_position = JsonXmlReaderPosition.ValueEndElement;
467 break;
468 }
469 case JsonXmlReaderPosition.ValueContent:
470 EndElementNode(m_jsonValueName, m_jsonNamespace);
471 m_position = JsonXmlReaderPosition.ValueEndElement;
472 return true;
473 case JsonXmlReaderPosition.Eof:
474 case JsonXmlReaderPosition.Closed:
475 case JsonXmlReaderPosition.Error:
476 return false;
477 }
478
479 while (m_parser.Read()) {
480 var jsonName = m_nameTable.Add(m_parser.ElementName);
481
482 switch (m_parser.ElementType) {
483 case JSONElementType.BeginObject:
484 if (!EnterJsonObject(jsonName, out elementName))
485 continue;
486
487 m_position = JsonXmlReaderPosition.BeginObject;
488 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
489 break;
490 case JSONElementType.EndObject:
491 if (!LeaveJsonScope(out elementName))
492 continue;
493
494 m_position = JsonXmlReaderPosition.EndObject;
495 EndElementNode(elementName, m_jsonNamespace);
496 break;
497 case JSONElementType.BeginArray:
498 if (!EnterJsonArray(jsonName, out elementName))
499 continue;
500
501 m_position = JsonXmlReaderPosition.BeginArray;
502 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
503 break;
504 case JSONElementType.EndArray:
505 if (!LeaveJsonScope(out elementName))
506 continue;
507
508 m_position = JsonXmlReaderPosition.EndArray;
509 EndElementNode(elementName, m_jsonNamespace);
510 break;
511 case JSONElementType.Value:
512 if (!VisitJsonValue(jsonName, out m_jsonValueName))
513 continue;
514
515 m_position = JsonXmlReaderPosition.ValueElement;
516 if (m_parser.ElementValue == null)
517 // generate empty element with xsi:nil="true" attribute
518 ElementNode(
519 m_jsonValueName,
520 m_jsonNamespace,
521 new[] {
522 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true)
523 },
524 true
525 );
526 else
527 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
528 break;
529 default:
530 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
531 }
532 return true;
533 }
534
535 m_position = JsonXmlReaderPosition.Eof;
536 return false;
537 } catch {
538 m_position = JsonXmlReaderPosition.Error;
539 throw;
540 }
541 }
542
543 void SaveJsonName() {
544 m_jsonNameStack.Push(new JsonContext {
545 skip = m_jsonSkip,
546 localName = m_jsonLocalName
547 });
548
549 }
550
551 bool EnterJsonObject(string name, out string elementName) {
552 SaveJsonName();
553 m_jsonSkip = false;
554
555 if (string.IsNullOrEmpty(name)) {
556 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
557 m_jsonLocalName = m_jsonArrayItemName;
558 } else {
559 m_jsonLocalName = name;
560 }
561
562 elementName = m_jsonLocalName;
563 return true;
564 }
565
566 /// <summary>
567 /// Called when JSON parser visits BeginArray ('[') element.
568 /// </summary>
569 /// <param name="name">Optional property name if the array is the member of an object</param>
570 /// <returns>true if element should be emited, false otherwise</returns>
571 bool EnterJsonArray(string name, out string elementName) {
572 SaveJsonName();
573
574 if (string.IsNullOrEmpty(name)) {
575 // m_jsonNameStack.Count == 1 means the root node
576 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
577 m_jsonLocalName = m_jsonArrayItemName;
578
579 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
580 } else {
581 m_jsonLocalName = name;
582 m_jsonSkip = m_jsonFlattenArrays;
583 }
584 elementName = m_jsonLocalName;
585
586 return !m_jsonSkip;
587 }
588
589 bool VisitJsonValue(string name, out string elementName) {
590 if (string.IsNullOrEmpty(name)) {
591 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
592 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
593 } else {
594 elementName = name;
595 }
596 return true;
597 }
598
599 bool LeaveJsonScope(out string elementName) {
600 elementName = m_jsonLocalName;
601 var skip = m_jsonSkip;
602
603 var prev = m_jsonNameStack.Pop();
604 m_jsonLocalName = prev.localName;
605 m_jsonSkip = prev.skip;
606
607 return !skip;
608 }
609
610 public override string ToString() {
611 switch (NodeType) {
612 case XmlNodeType.Element:
613 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{ConvertValueToString(x.Value)}'"))} {(IsEmptyElement ? "/" : "")}>";
614 case XmlNodeType.Attribute:
615 return $"@{Name}";
616 case XmlNodeType.Text:
617 return $"{Value}";
618 case XmlNodeType.CDATA:
619 return $"<![CDATA[{Value}]]>";
620 case XmlNodeType.EntityReference:
621 return $"&{Name};";
622 case XmlNodeType.EndElement:
623 return $"</{Name}>";
624 default:
625 return $".{NodeType} {Name} {Value}";
626 }
627 }
628 }
629 }
@@ -0,0 +1,66
1
2 using System;
3 using System.Xml;
4
5 namespace Implab.Formats.JSON {
6 /// <summary>
7 /// Набор Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² для <see cref="JSONXmlReader"/>, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ процСссом
8 /// ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ†ΠΈΠΈ <c>JSON</c> Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
9 /// </summary>
10 public class JSONXmlReaderOptions : ICloneable {
11 /// <summary>
12 /// ΠŸΡ€ΠΎΡΡ‚Ρ€Π°Π½ΡΡ‚Π²ΠΎ ΠΈΠΌΠ΅Π½ Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°Ρ‚ΡŒΡΡ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹Π΅ элСмСнты Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
13 /// </summary>
14 public string NamespaceURI {
15 get;
16 set;
17 }
18
19 /// <summary>
20 /// Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ массивы ΠΊΠ°ΠΊ мноТСствСнныС элСмСнты (ΡƒΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности), ΠΈΠ½Π°Ρ‡Π΅ массив
21 /// прСдставляСтся Π² Π²ΠΈΠ΄Π΅ ΡƒΠ·Π»Π°, Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌΠΈ элСмСнтами ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΡΠ²Π»ΡΡŽΡ‚ΡΡ элСмСнты массива, ΠΈΠΌΠ΅Π½Π° Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… элСмСнтов
22 /// ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ свойством <see cref="ArrayItemName"/>. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>false</c>.
23 /// </summary>
24 public bool FlattenArrays {
25 get;
26 set;
27 }
28
29 /// <summary>
30 /// ΠŸΡ€Π΅Ρ„ΠΈΠΊΡ, для ΡƒΠ·Π»ΠΎΠ² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
31 /// </summary>
32 public string NodesPrefix {
33 get;
34 set;
35 }
36
37 /// <summary>
38 /// Имя ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ элСмСнта Π² xml Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅
39 /// </summary>
40 public string RootName {
41 get;
42 set;
43 }
44
45 /// <summary>
46 /// Имя элСмСнта для массивов, Ссли Π½Π΅ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π° опция <see cref="FlattenArrays"/>.
47 /// По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>item</c>.
48 /// </summary>
49 public string ArrayItemName {
50 get;
51 set;
52 }
53
54 /// <summary>
55 /// Π’Π°Π±Π»ΠΈΡ†Π° Π°Ρ‚ΠΎΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… строк для построСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
56 /// </summary>
57 public XmlNameTable NameTable {
58 get;
59 set;
60 }
61
62 public object Clone() {
63 return MemberwiseClone();
64 }
65 }
66 }
@@ -0,0 +1,22
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Xml {
8 public enum JsonXmlReaderPosition {
9 Initial,
10 Declaration,
11 BeginArray,
12 BeginObject,
13 EndArray,
14 EndObject,
15 ValueElement,
16 ValueContent,
17 ValueEndElement,
18 Eof,
19 Closed,
20 Error
21 }
22 }
@@ -0,0 +1,111
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Xml;
7
8 namespace Implab.Xml {
9 public class XmlNameContext {
10 public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
11 public const string XmlnsPrefix = "xmlns";
12 public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
13 public const string XmlPrefix = "xml";
14 public const string XsiNamespace = "http://www.w3.org/2001/XMLSchema-instance";
15 public const string XsiPrefix = "xsi";
16
17 readonly static char[] _qNameDelim = new[] { ':' };
18
19 Dictionary<string, string> m_ns2prefix;
20 Dictionary<string, string> m_prefix2ns;
21 int m_nextPrefix = 1;
22
23 public XmlNameContext ParentContext { get; private set; }
24
25 public XmlNameContext(XmlNameContext parent) {
26 ParentContext = parent;
27 if (parent == null) {
28 DefinePrefixNoCheck(XmlnsNamespace, XmlnsPrefix);
29 DefinePrefixNoCheck(XmlNamespace, XmlPrefix);
30 } else {
31 m_nextPrefix = parent.m_nextPrefix;
32 }
33 }
34
35 public bool LookupNamespacePrefix(string ns, out string prefix) {
36 if (ns == null)
37 ns = string.Empty;
38
39 prefix = null;
40 for (var ctx = this; ctx != null; ctx = ctx.ParentContext) {
41 if (ctx.m_ns2prefix?.TryGetValue(ns, out prefix) == true) {
42 if (ctx != this) // cache for the future use
43 DefinePrefixNoCheck(ns, prefix);
44 return true;
45 }
46 }
47 return false;
48 }
49
50 public string CreateNamespacePrefix(string ns) {
51 var prefix = $"p{m_nextPrefix++}";
52 DefinePrefixNoCheck(ns, prefix);
53 return prefix;
54 }
55
56 void DefinePrefixNoCheck(string ns, string prefix) {
57 if (ns == null)
58 ns = string.Empty;
59 if (prefix == null)
60 prefix = string.Empty;
61
62 if (m_ns2prefix == null)
63 m_ns2prefix = new Dictionary<string, string>();
64 m_ns2prefix[ns] = prefix;
65
66 if (m_prefix2ns == null)
67 m_prefix2ns = new Dictionary<string, string>();
68 m_prefix2ns[prefix] = ns;
69 }
70
71 public void DefinePrefix(string ns, string prefix) {
72 // according to https://www.w3.org/TR/xml-names/#ns-decl
73
74 // It MUST NOT be declared . Other prefixes MUST NOT be bound to this namespace name, and it MUST NOT be declared as the default namespace
75 if (ns == XmlnsNamespace)
76 throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
77
78 // It MAY, but need not, be declared, and MUST NOT be bound to any other namespace name
79 if (ns == XmlNamespace && prefix != XmlPrefix)
80 throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
81
82 // add mapping
83 DefinePrefixNoCheck(ns, prefix);
84 }
85
86 public string ResolvePrefix(string prefix) {
87 if (prefix == null)
88 prefix = string.Empty;
89 string ns = null;
90 for(var ctx = this; ctx != null; ctx = ctx.ParentContext) {
91 if (ctx.m_prefix2ns?.TryGetValue(prefix, out ns) == true) {
92 if (ctx != this) // cache for the future use
93 DefinePrefixNoCheck(ns, prefix);
94 return ns;
95 }
96 }
97 return null;
98 }
99
100 public XmlQualifiedName Resolve(string name) {
101 Safe.ArgumentNotEmpty(name, nameof(name));
102 var parts = name.Split(_qNameDelim, 2, StringSplitOptions.RemoveEmptyEntries);
103
104 if (parts.Length == 2) {
105 return new XmlQualifiedName(parts[1], ResolvePrefix(parts[0]));
106 } else {
107 return new XmlQualifiedName(parts[0], ResolvePrefix(string.Empty));
108 }
109 }
110 }
111 }
@@ -0,0 +1,22
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Xml;
7
8 namespace Implab.Xml {
9 public class XmlSimpleAttribute {
10 public XmlSimpleAttribute(string name, string ns, string prefix, object value) {
11 QName = new XmlQualifiedName(name, ns);
12 Prefix = prefix;
13 Value = value;
14 }
15
16 public XmlQualifiedName QName { get; set; }
17
18 public string Prefix { get; set; }
19
20 public object Value { get; set; }
21 }
22 }
@@ -1,20 +1,23
1 1 syntax: glob
2 2 Implab.Test/bin/
3 3 *.user
4 4 Implab.Test/obj/
5 5 *.userprefs
6 6 Implab/bin/
7 7 Implab/obj/
8 8 TestResults/
9 9 Implab.Fx/obj/
10 10 Implab.Fx/bin/
11 11 Implab.Fx.Test/bin/
12 12 Implab.Fx.Test/obj/
13 13 _ReSharper.Implab/
14 14 Implab.Diagnostics.Interactive/bin/
15 15 Implab.Diagnostics.Interactive/obj/
16 16 MonoPlay/bin/
17 17 MonoPlay/obj/
18 18 Implab.Test/Implab.Format.Test/bin/
19 19 Implab.Test/Implab.Format.Test/obj/
20 20 *.suo
21 Implab.Format.Test/bin/
22 Implab.Format.Test/obj/
23 packages/
@@ -1,55 +1,57
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProductVersion>8.0.30703</ProductVersion>
7 7 <SchemaVersion>2.0</SchemaVersion>
8 8 <ProjectGuid>{4D364996-7ECD-4193-8F90-F223FFEA49DA}</ProjectGuid>
9 9 <OutputType>Library</OutputType>
10 10 <RootNamespace>Implab.Format.Test</RootNamespace>
11 11 <AssemblyName>Implab.Format.Test</AssemblyName>
12 12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 13 <ReleaseVersion>0.2</ReleaseVersion>
14 14 </PropertyGroup>
15 15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 16 <DebugSymbols>true</DebugSymbols>
17 17 <DebugType>full</DebugType>
18 18 <Optimize>false</Optimize>
19 19 <OutputPath>bin\Debug</OutputPath>
20 20 <DefineConstants>DEBUG;</DefineConstants>
21 21 <ErrorReport>prompt</ErrorReport>
22 22 <WarningLevel>4</WarningLevel>
23 23 <ConsolePause>false</ConsolePause>
24 24 </PropertyGroup>
25 25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 26 <DebugType>full</DebugType>
27 27 <Optimize>true</Optimize>
28 28 <OutputPath>bin\Release</OutputPath>
29 29 <ErrorReport>prompt</ErrorReport>
30 30 <WarningLevel>4</WarningLevel>
31 31 <ConsolePause>false</ConsolePause>
32 32 </PropertyGroup>
33 33 <ItemGroup>
34 <Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
35 <HintPath>..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
36 <Private>True</Private>
37 </Reference>
34 38 <Reference Include="System" />
35 <Reference Include="nunit.framework">
36 <HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
37 </Reference>
39 <Reference Include="System.Xml" />
38 40 </ItemGroup>
39 41 <ItemGroup>
40 42 <Compile Include="JsonTests.cs" />
41 43 </ItemGroup>
42 44 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
43 45 <ItemGroup>
44 <ProjectReference Include="..\..\Implab\Implab.csproj">
46 <ProjectReference Include="..\Implab\Implab.csproj">
45 47 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
46 48 <Name>Implab</Name>
47 49 </ProjectReference>
48 50 </ItemGroup>
49 51 <ItemGroup>
50 <None Include="packages.config" />
52 <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
51 53 </ItemGroup>
52 54 <ItemGroup>
53 <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
55 <None Include="packages.config" />
54 56 </ItemGroup>
55 57 </Project> No newline at end of file
@@ -1,88 +1,145
1 1 using NUnit.Framework;
2 2 using System;
3 3 using Implab.Formats.JSON;
4 4 using Implab.Automaton;
5 using Implab.Xml;
6 using System.Xml;
7 using System.Text;
5 8
6 9 namespace Implab.Format.Test {
7 10 [TestFixture]
8 11 public class JsonTests {
9 12 [Test]
10 13 public void TestScannerValidTokens() {
11 14 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
12 15
13 16 Tuple<JsonTokenType,object>[] expexted = {
14 17 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
15 18 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
16 19 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
17 20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
18 21 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
19 22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
20 23 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
21 24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
22 25 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
23 26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
24 27 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
25 28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
26 29 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
27 30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
28 31 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
29 32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
30 33 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
31 34 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
32 35 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
33 36 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
34 37 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
35 38 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
36 39 };
37 40
38 41 object value;
39 42 JsonTokenType tokenType;
40 43 for (var i = 0; i < expexted.Length; i++) {
41 44
42 45 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
43 46 Assert.AreEqual(expexted[i].Item1, tokenType);
44 47 Assert.AreEqual(expexted[i].Item2, value);
45 48 }
46 49
47 50 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
48 51 }
49 52 }
50 53
51 54 [Test]
52 55 public void TestScannerBadTokens() {
53 56 var bad = new [] {
54 57 " 1",
55 58 " literal",
56 59 " \"",
57 60 "\"unclosed string",
58 61 "1.bad",
59 62 "001", // should be read as three numbers
60 63 "--10",
61 64 "+10",
62 65 "1.0.0",
63 66 "1e1.0",
64 67 "l1teral0",
65 68 ".123",
66 69 "-.123"
67 70 };
68 71
69 foreach (var json in bad)
72 foreach (var json in bad) {
70 73 using (var scanner = new JSONScanner(json)) {
71 74 try {
72 75 object value;
73 76 JsonTokenType token;
74 77 scanner.ReadToken(out value, out token);
75 78 if (!Object.Equals(value,json)) {
76 79 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
77 80 continue;
78 81 }
79 82 Assert.Fail("Token '{0}' shouldn't pass", json);
80 83 } catch (ParserException e) {
81 84 Console.WriteLine(e.Message);
82 85 }
83 86 }
87 }
88 }
84 89
90 [Test]
91 public void JsonXmlReaderSimpleTest() {
92 var json = "\"some text\"";
93 //Console.WriteLine($"JSON: {json}");
94 //Console.WriteLine("XML");
95 /*using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", RootName = "string", NodesPrefix = "json" })) {
96 Assert.AreEqual(xmlReader.ReadState, System.Xml.ReadState.Initial);
97
98 AssertRead(xmlReader, XmlNodeType.XmlDeclaration);
99 AssertRead(xmlReader, XmlNodeType.Element);
100 AssertRead(xmlReader, XmlNodeType.Text);
101 AssertRead(xmlReader, XmlNodeType.EndElement);
102 Assert.IsFalse(xmlReader.Read());
103 }*/
104
105 //DumpJsonParse("\"text value\"");
106 //DumpJsonParse("null");
107 //DumpJsonParse("true");
108 //DumpJsonParse("{}");
109 //DumpJsonParse("[]");
110 DumpJsonParse("{\"one\":1, \"two\":2}");
111 DumpJsonParse("[1,2,3]");
112 DumpJsonParse("[{\"info\": [7,8,9]}]");
113 DumpJsonFlatParse("[1,2,[3,4],{\"info\": [5,6]},{\"num\": [7,8,null]}, null,[null]]");
114 }
115
116 void AssertRead(XmlReader reader, XmlNodeType expected) {
117 Assert.IsTrue(reader.Read());
118 Console.WriteLine($"{new string(' ', reader.Depth*2)}{reader}");
119 Assert.AreEqual(expected, reader.NodeType);
120 }
121
122 void DumpJsonParse(string json) {
123 Console.WriteLine($"JSON: {json}");
124 Console.WriteLine("XML");
125 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
126 while (xmlReader.Read())
127 Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
128 }
129 }
130
131 void DumpJsonFlatParse(string json) {
132 Console.WriteLine($"JSON: {json}");
133 Console.WriteLine("XML");
134 using (var xmlWriter = XmlWriter.Create(Console.Out, new XmlWriterSettings {
135 Indent = true,
136 CloseOutput = false,
137 ConformanceLevel = ConformanceLevel.Document
138 }))
139 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
140 xmlWriter.WriteNode(xmlReader, false);
141 }
85 142 }
86 143 }
87 144 }
88 145
@@ -1,4 +1,4
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <packages>
3 <package id="NUnit" version="2.6.4" targetFramework="net45" />
3 <package id="NUnit" version="3.8.1" targetFramework="net45" />
4 4 </packages> No newline at end of file
@@ -1,90 +1,88
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProductVersion>8.0.30703</ProductVersion>
7 7 <SchemaVersion>2.0</SchemaVersion>
8 8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
9 9 <OutputType>Library</OutputType>
10 10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 11 <RootNamespace>Implab.Test</RootNamespace>
12 12 <AssemblyName>Implab.Test</AssemblyName>
13 13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 14 <FileAlignment>512</FileAlignment>
15 15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16 16 <TargetFrameworkProfile />
17 17 </PropertyGroup>
18 18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 19 <DebugSymbols>true</DebugSymbols>
20 20 <DebugType>full</DebugType>
21 21 <Optimize>false</Optimize>
22 22 <OutputPath>bin\Debug\</OutputPath>
23 23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 24 <ErrorReport>prompt</ErrorReport>
25 25 <WarningLevel>4</WarningLevel>
26 26 <Prefer32Bit>false</Prefer32Bit>
27 27 </PropertyGroup>
28 28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 29 <DebugType>pdbonly</DebugType>
30 30 <Optimize>true</Optimize>
31 31 <OutputPath>bin\Release\</OutputPath>
32 32 <DefineConstants>TRACE</DefineConstants>
33 33 <ErrorReport>prompt</ErrorReport>
34 34 <WarningLevel>4</WarningLevel>
35 35 <Prefer32Bit>false</Prefer32Bit>
36 36 </PropertyGroup>
37 37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 38 <DebugSymbols>true</DebugSymbols>
39 39 <DebugType>full</DebugType>
40 40 <Optimize>false</Optimize>
41 41 <OutputPath>bin\Debug\</OutputPath>
42 42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 43 <ErrorReport>prompt</ErrorReport>
44 44 <WarningLevel>4</WarningLevel>
45 45 <Prefer32Bit>false</Prefer32Bit>
46 46 </PropertyGroup>
47 47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
48 48 <DebugType>pdbonly</DebugType>
49 49 <Optimize>true</Optimize>
50 50 <OutputPath>bin\Release\</OutputPath>
51 51 <DefineConstants>TRACE</DefineConstants>
52 52 <ErrorReport>prompt</ErrorReport>
53 53 <WarningLevel>4</WarningLevel>
54 54 <Prefer32Bit>false</Prefer32Bit>
55 55 </PropertyGroup>
56 56 <ItemGroup>
57 57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
58 58 <Reference Include="System" />
59 59 <Reference Include="System.Core">
60 60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
61 61 </Reference>
62 62 </ItemGroup>
63 63 <ItemGroup>
64 64 <Compile Include="AsyncTests.cs" />
65 65 <Compile Include="CancelationTests.cs" />
66 66 <Compile Include="Mock\MockPollingComponent.cs" />
67 67 <Compile Include="Mock\MockRunnableComponent.cs" />
68 68 <Compile Include="PollingComponentTests.cs" />
69 69 <Compile Include="PromiseHelper.cs" />
70 70 <Compile Include="Properties\AssemblyInfo.cs" />
71 71 <Compile Include="RunnableComponentTests.cs" />
72 72 </ItemGroup>
73 73 <ItemGroup>
74 74 <ProjectReference Include="..\Implab\Implab.csproj">
75 75 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
76 76 <Name>Implab</Name>
77 77 </ProjectReference>
78 78 </ItemGroup>
79 <ItemGroup>
80 <Folder Include="Implab.Format.Test\" />
81 </ItemGroup>
79 <ItemGroup />
82 80 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
83 81 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
84 82 Other similar extension points exist, see Microsoft.Common.targets.
85 83 <Target Name="BeforeBuild">
86 84 </Target>
87 85 <Target Name="AfterBuild">
88 86 </Target>
89 87 -->
90 88 </Project> No newline at end of file
@@ -1,270 +1,260
1 1 ο»Ώ
2 Microsoft Visual Studio Solution File, Format Version 11.00
3 # Visual Studio 2010
2 Microsoft Visual Studio Solution File, Format Version 12.00
3 # Visual Studio 14
4 VisualStudioVersion = 14.0.25420.1
5 MinimumVisualStudioVersion = 10.0.40219.1
4 6 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab", "Implab\Implab.csproj", "{F550F1F8-8746-4AD0-9614-855F4C4B7F05}"
5 7 EndProject
6 8 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CE8D8D18-437A-445C-B662-4C2CE79A76F6}"
7 9 ProjectSection(SolutionItems) = preProject
8 10 Implab.vsmdi = Implab.vsmdi
9 11 Local.testsettings = Local.testsettings
10 12 TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
11 13 EndProjectSection
12 14 EndProject
13 15 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Test", "Implab.Test\Implab.Test.csproj", "{63F92C0C-61BF-48C0-A377-8D67C3C661D0}"
14 16 EndProject
15 17 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx", "Implab.Fx\Implab.Fx.csproj", "{06E706F8-6881-43EB-927E-FFC503AF6ABC}"
16 18 EndProject
17 19 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Fx.Test", "Implab.Fx.Test\Implab.Fx.Test.csproj", "{2F31E405-E267-4195-A05D-574093C21209}"
18 20 EndProject
21 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Implab.Format.Test", "Implab.Format.Test\Implab.Format.Test.csproj", "{4D364996-7ECD-4193-8F90-F223FFEA49DA}"
22 EndProject
19 23 Global
20 24 GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 Debug 4.5|Any CPU = Debug 4.5|Any CPU
21 26 Debug|Any CPU = Debug|Any CPU
27 Release 4.5|Any CPU = Release 4.5|Any CPU
22 28 Release|Any CPU = Release|Any CPU
23 Debug 4.5|Any CPU = Debug 4.5|Any CPU
24 Release 4.5|Any CPU = Release 4.5|Any CPU
25 29 EndGlobalSection
26 30 GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
32 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
33 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
36 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
37 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
39 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
40 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
41 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
44 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
45 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
27 47 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
28 48 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
29 49 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 50 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 51 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
32 52 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
33 53 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 54 {06E706F8-6881-43EB-927E-FFC503AF6ABC}.Release|Any CPU.Build.0 = Release|Any CPU
35 55 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
36 56 {2F31E405-E267-4195-A05D-574093C21209}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
37 57 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 58 {2F31E405-E267-4195-A05D-574093C21209}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 59 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
40 60 {2F31E405-E267-4195-A05D-574093C21209}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
41 61 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 62 {2F31E405-E267-4195-A05D-574093C21209}.Release|Any CPU.Build.0 = Release|Any CPU
43 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
44 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
45 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
48 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
49 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 {63F92C0C-61BF-48C0-A377-8D67C3C661D0}.Release|Any CPU.Build.0 = Release|Any CPU
51 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.ActiveCfg = Debug 4.5|Any CPU
52 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug 4.5|Any CPU.Build.0 = Debug 4.5|Any CPU
53 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.ActiveCfg = Release 4.5|Any CPU
56 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release 4.5|Any CPU.Build.0 = Release 4.5|Any CPU
57 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 {F550F1F8-8746-4AD0-9614-855F4C4B7F05}.Release|Any CPU.Build.0 = Release|Any CPU
63 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.ActiveCfg = Debug|Any CPU
64 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug 4.5|Any CPU.Build.0 = Debug|Any CPU
65 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release 4.5|Any CPU.ActiveCfg = Release|Any CPU
68 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release 4.5|Any CPU.Build.0 = Release|Any CPU
69 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
70 {4D364996-7ECD-4193-8F90-F223FFEA49DA}.Release|Any CPU.Build.0 = Release|Any CPU
59 71 EndGlobalSection
60 GlobalSection(NestedProjects) = preSolution
72 GlobalSection(SolutionProperties) = preSolution
73 HideSolutionNode = FALSE
61 74 EndGlobalSection
62 75 GlobalSection(MonoDevelopProperties) = preSolution
63 76 StartupItem = Implab\Implab.csproj
64 77 Policies = $0
65 78 $0.CSharpFormattingPolicy = $1
66 79 $1.IndentSwitchBody = True
67 80 $1.NamespaceBraceStyle = EndOfLine
68 81 $1.ClassBraceStyle = EndOfLine
69 82 $1.InterfaceBraceStyle = EndOfLine
70 83 $1.StructBraceStyle = EndOfLine
71 84 $1.EnumBraceStyle = EndOfLine
72 85 $1.MethodBraceStyle = EndOfLine
73 86 $1.ConstructorBraceStyle = EndOfLine
74 87 $1.DestructorBraceStyle = EndOfLine
75 88 $1.BeforeMethodDeclarationParentheses = False
76 89 $1.BeforeMethodCallParentheses = False
77 90 $1.BeforeConstructorDeclarationParentheses = False
78 91 $1.NewLineBeforeConstructorInitializerColon = NewLine
79 92 $1.NewLineAfterConstructorInitializerColon = SameLine
80 93 $1.BeforeIndexerDeclarationBracket = False
81 94 $1.BeforeDelegateDeclarationParentheses = False
82 95 $1.NewParentheses = False
83 96 $1.SpacesBeforeBrackets = False
84 97 $1.inheritsSet = Mono
85 98 $1.inheritsScope = text/x-csharp
86 99 $1.scope = text/x-csharp
87 $0.TextStylePolicy = $2
100 $0.TextStylePolicy = $6
88 101 $2.FileWidth = 120
89 102 $2.EolMarker = Unix
90 103 $2.inheritsSet = VisualStudio
91 104 $2.inheritsScope = text/plain
92 105 $2.scope = text/x-csharp
93 106 $0.DotNetNamingPolicy = $3
94 107 $3.DirectoryNamespaceAssociation = PrefixedHierarchical
95 108 $3.ResourceNamePolicy = MSBuild
96 $0.TextStylePolicy = $4
97 109 $4.FileWidth = 120
98 110 $4.TabsToSpaces = False
99 111 $4.inheritsSet = VisualStudio
100 112 $4.inheritsScope = text/plain
101 113 $4.scope = application/xml
102 114 $0.XmlFormattingPolicy = $5
103 115 $5.inheritsSet = Mono
104 116 $5.inheritsScope = application/xml
105 117 $5.scope = application/xml
106 $0.TextStylePolicy = $6
107 118 $6.FileWidth = 120
108 119 $6.TabsToSpaces = False
109 120 $6.inheritsSet = VisualStudio
110 121 $6.inheritsScope = text/plain
111 122 $6.scope = text/plain
112 123 $0.NameConventionPolicy = $7
113 124 $7.Rules = $8
114 $8.NamingRule = $9
125 $8.NamingRule = $34
115 126 $9.Name = Namespaces
116 127 $9.AffectedEntity = Namespace
117 128 $9.VisibilityMask = VisibilityMask
118 129 $9.NamingStyle = PascalCase
119 130 $9.IncludeInstanceMembers = True
120 131 $9.IncludeStaticEntities = True
121 $8.NamingRule = $10
122 132 $10.Name = Types
123 133 $10.AffectedEntity = Class, Struct, Enum, Delegate
124 134 $10.VisibilityMask = VisibilityMask
125 135 $10.NamingStyle = PascalCase
126 136 $10.IncludeInstanceMembers = True
127 137 $10.IncludeStaticEntities = True
128 $8.NamingRule = $11
129 138 $11.Name = Interfaces
130 139 $11.RequiredPrefixes = $12
131 140 $12.String = I
132 141 $11.AffectedEntity = Interface
133 142 $11.VisibilityMask = VisibilityMask
134 143 $11.NamingStyle = PascalCase
135 144 $11.IncludeInstanceMembers = True
136 145 $11.IncludeStaticEntities = True
137 $8.NamingRule = $13
138 146 $13.Name = Attributes
139 147 $13.RequiredSuffixes = $14
140 148 $14.String = Attribute
141 149 $13.AffectedEntity = CustomAttributes
142 150 $13.VisibilityMask = VisibilityMask
143 151 $13.NamingStyle = PascalCase
144 152 $13.IncludeInstanceMembers = True
145 153 $13.IncludeStaticEntities = True
146 $8.NamingRule = $15
147 154 $15.Name = Event Arguments
148 155 $15.RequiredSuffixes = $16
149 156 $16.String = EventArgs
150 157 $15.AffectedEntity = CustomEventArgs
151 158 $15.VisibilityMask = VisibilityMask
152 159 $15.NamingStyle = PascalCase
153 160 $15.IncludeInstanceMembers = True
154 161 $15.IncludeStaticEntities = True
155 $8.NamingRule = $17
156 162 $17.Name = Exceptions
157 163 $17.RequiredSuffixes = $18
158 164 $18.String = Exception
159 165 $17.AffectedEntity = CustomExceptions
160 166 $17.VisibilityMask = VisibilityMask
161 167 $17.NamingStyle = PascalCase
162 168 $17.IncludeInstanceMembers = True
163 169 $17.IncludeStaticEntities = True
164 $8.NamingRule = $19
165 170 $19.Name = Methods
166 171 $19.AffectedEntity = Methods
167 172 $19.VisibilityMask = VisibilityMask
168 173 $19.NamingStyle = PascalCase
169 174 $19.IncludeInstanceMembers = True
170 175 $19.IncludeStaticEntities = True
171 $8.NamingRule = $20
172 176 $20.Name = Static Readonly Fields
173 177 $20.AffectedEntity = ReadonlyField
174 178 $20.VisibilityMask = Internal, Protected, Public
175 179 $20.NamingStyle = CamelCase
176 180 $20.IncludeInstanceMembers = False
177 181 $20.IncludeStaticEntities = True
178 $8.NamingRule = $21
179 182 $21.Name = Fields (Non Private)
180 183 $21.AffectedEntity = Field
181 184 $21.VisibilityMask = Internal, Public
182 185 $21.NamingStyle = CamelCase
183 186 $21.IncludeInstanceMembers = True
184 187 $21.IncludeStaticEntities = True
185 $8.NamingRule = $22
186 188 $22.Name = ReadOnly Fields (Non Private)
187 189 $22.AffectedEntity = ReadonlyField
188 190 $22.VisibilityMask = Internal, Public
189 191 $22.NamingStyle = CamelCase
190 192 $22.IncludeInstanceMembers = True
191 193 $22.IncludeStaticEntities = False
192 $8.NamingRule = $23
193 194 $23.Name = Fields (Private)
194 195 $23.RequiredPrefixes = $24
195 196 $24.String = m_
196 197 $23.AffectedEntity = Field, ReadonlyField
197 198 $23.VisibilityMask = Private, Protected
198 199 $23.NamingStyle = CamelCase
199 200 $23.IncludeInstanceMembers = True
200 201 $23.IncludeStaticEntities = False
201 $8.NamingRule = $25
202 202 $25.Name = Static Fields (Private)
203 203 $25.RequiredPrefixes = $26
204 204 $26.String = _
205 205 $25.AffectedEntity = Field
206 206 $25.VisibilityMask = Private
207 207 $25.NamingStyle = CamelCase
208 208 $25.IncludeInstanceMembers = False
209 209 $25.IncludeStaticEntities = True
210 $8.NamingRule = $27
211 210 $27.Name = ReadOnly Fields (Private)
212 211 $27.RequiredPrefixes = $28
213 212 $28.String = m_
214 213 $27.AffectedEntity = ReadonlyField
215 214 $27.VisibilityMask = Private, Protected
216 215 $27.NamingStyle = CamelCase
217 216 $27.IncludeInstanceMembers = True
218 217 $27.IncludeStaticEntities = False
219 $8.NamingRule = $29
220 218 $29.Name = Constant Fields
221 219 $29.AffectedEntity = ConstantField
222 220 $29.VisibilityMask = VisibilityMask
223 221 $29.NamingStyle = AllUpper
224 222 $29.IncludeInstanceMembers = True
225 223 $29.IncludeStaticEntities = True
226 $8.NamingRule = $30
227 224 $30.Name = Properties
228 225 $30.AffectedEntity = Property
229 226 $30.VisibilityMask = VisibilityMask
230 227 $30.NamingStyle = PascalCase
231 228 $30.IncludeInstanceMembers = True
232 229 $30.IncludeStaticEntities = True
233 $8.NamingRule = $31
234 230 $31.Name = Events
235 231 $31.AffectedEntity = Event
236 232 $31.VisibilityMask = VisibilityMask
237 233 $31.NamingStyle = PascalCase
238 234 $31.IncludeInstanceMembers = True
239 235 $31.IncludeStaticEntities = True
240 $8.NamingRule = $32
241 236 $32.Name = Enum Members
242 237 $32.AffectedEntity = EnumMember
243 238 $32.VisibilityMask = VisibilityMask
244 239 $32.NamingStyle = PascalCase
245 240 $32.IncludeInstanceMembers = True
246 241 $32.IncludeStaticEntities = True
247 $8.NamingRule = $33
248 242 $33.Name = Parameters
249 243 $33.AffectedEntity = Parameter, LocalVariable
250 244 $33.VisibilityMask = VisibilityMask
251 245 $33.NamingStyle = CamelCase
252 246 $33.IncludeInstanceMembers = True
253 247 $33.IncludeStaticEntities = True
254 $8.NamingRule = $34
255 248 $34.Name = Type Parameters
256 249 $34.RequiredPrefixes = $35
257 250 $35.String = T
258 251 $34.AffectedEntity = TypeParameter
259 252 $34.VisibilityMask = VisibilityMask
260 253 $34.NamingStyle = PascalCase
261 254 $34.IncludeInstanceMembers = True
262 255 $34.IncludeStaticEntities = True
263 256 EndGlobalSection
264 257 GlobalSection(TestCaseManagementSettings) = postSolution
265 258 CategoryFile = Implab.vsmdi
266 259 EndGlobalSection
267 GlobalSection(SolutionProperties) = preSolution
268 HideSolutionNode = FALSE
269 EndGlobalSection
270 260 EndGlobal
@@ -1,293 +1,294
1 1 using System;
2 2 using System.Diagnostics;
3 3 using System.IO;
4 4 using Implab.Automaton;
5 5 using Implab.Automaton.RegularExpressions;
6 6 using System.Linq;
7 7 using Implab.Components;
8 8 using System.Collections.Generic;
9 9
10 10 namespace Implab.Formats.JSON {
11 11 /// <summary>
12 12 /// Pull парсСр JSON Π΄Π°Π½Π½Ρ‹Ρ….
13 13 /// </summary>
14 14 /// <remarks>
15 15 /// Π‘Π»Π΅Π΄ΡƒΠ΅Ρ‚ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ†ΠΈΡŽ свойства <see cref="Level"/>,
16 16 /// ΠΎΠ½ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², ΠΎΠ΄Π½Π°ΠΊΠΎ Π·Π°ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ
17 17 /// элСмСнт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΈ массива ΠΈΠΌΠ΅Π΅Ρ‚ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ мСньшС, Ρ‡Π΅ΠΌ сам ΠΎΠ±ΡŠΠ΅ΠΊΡ‚.
18 18 /// <code>
19 19 /// { // Level = 1
20 20 /// "name" : "Peter", // Level = 1
21 21 /// "address" : { // Level = 2
22 22 /// city : "Stern" // Level = 2
23 23 /// } // Level = 1
24 24 /// } // Level = 0
25 25 /// </code>
26 26 /// </remarks>
27 27 public class JSONParser : Disposable {
28 28
29 29 enum MemberContext {
30 30 MemberName,
31 31 MemberValue
32 32 }
33 33
34 34 #region Parser rules
35 35 struct ParserContext {
36 36 readonly int[,] m_dfa;
37 37 int m_state;
38 38
39 39 readonly JSONElementContext m_elementContext;
40 40
41 41 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
42 42 m_dfa = dfa;
43 43 m_state = state;
44 44 m_elementContext = context;
45 45 }
46 46
47 47 public bool Move(JsonTokenType token) {
48 48 var next = m_dfa[m_state, (int)token];
49 49 if (next == AutomatonConst.UNREACHABLE_STATE)
50 50 return false;
51 51 m_state = next;
52 52 return true;
53 53 }
54 54
55 55 public JSONElementContext ElementContext {
56 56 get { return m_elementContext; }
57 57 }
58 58 }
59 59
60 60 static readonly ParserContext _jsonContext;
61 61 static readonly ParserContext _objectContext;
62 62 static readonly ParserContext _arrayContext;
63 63
64 64 static JSONParser() {
65 65
66 66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
68 68
69 69 var objectExpression = memberExpression
70 70 .Cat(
71 71 MakeToken(JsonTokenType.ValueSeparator)
72 72 .Cat(memberExpression)
73 73 .EClosure()
74 74 )
75 75 .Optional()
76 76 .Cat(MakeToken(JsonTokenType.EndObject))
77 77 .End();
78 78
79 79 var arrayExpression = valueExpression
80 80 .Cat(
81 81 MakeToken(JsonTokenType.ValueSeparator)
82 82 .Cat(valueExpression)
83 83 .EClosure()
84 84 )
85 85 .Optional()
86 86 .Cat(MakeToken(JsonTokenType.EndArray))
87 87 .End();
88 88
89 89 var jsonExpression = valueExpression.End();
90 90
91 91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
92 92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
93 93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
94 94 }
95 95
96 96 static Token MakeToken(params JsonTokenType[] input) {
97 97 return Token.New( input.Select(t => (int)t).ToArray() );
98 98 }
99 99
100 100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
101 101
102 102 var dfa = new DFATable();
103 103 var builder = new RegularExpressionVisitor(dfa);
104 104 expr.Accept(builder);
105 105 builder.BuildDFA();
106 106
107 107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
108 108 }
109 109
110 110 #endregion
111 111
112 112 readonly JSONScanner m_scanner;
113 MemberContext m_memberContext;
113 // json starts from the value context and may content even a single literal
114 MemberContext m_memberContext = MemberContext.MemberValue;
114 115
115 116 JSONElementType m_elementType;
116 117 object m_elementValue;
117 118 string m_memberName = String.Empty;
118 119
119 120 Stack<ParserContext> m_stack = new Stack<ParserContext>();
120 121 ParserContext m_context = _jsonContext;
121 122
122 123 /// <summary>
123 124 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ парсСр Π½Π° основС строки, содСрТащСй JSON
124 125 /// </summary>
125 126 /// <param name="text"></param>
126 127 public JSONParser(string text) {
127 128 Safe.ArgumentNotEmpty(text, "text");
128 129 m_scanner = new JSONScanner(text);
129 130 }
130 131
131 132 /// <summary>
132 133 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр парсСра, Π½Π° основС тСкстового ΠΏΠΎΡ‚ΠΎΠΊΠ°.
133 134 /// </summary>
134 135 /// <param name="reader">ВСкстовый ΠΏΠΎΡ‚ΠΎΠΊ.</param>
135 136 public JSONParser(TextReader reader) {
136 137 Safe.ArgumentNotNull(reader, "reader");
137 138 m_scanner = new JSONScanner(reader);
138 139 }
139 140
140 141 public int Level {
141 142 get { return m_stack.Count; }
142 143 }
143 144
144 145 /// <summary>
145 146 /// Π’ΠΈΠΏ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ элСмСнта Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ стоит парсСр.
146 147 /// </summary>
147 148 public JSONElementType ElementType {
148 149 get { return m_elementType; }
149 150 }
150 151
151 152 /// <summary>
152 153 /// Имя элСмСнта - имя свойства Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°. Для элСмСнтов массивов ΠΈ ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ всСгда
153 154 /// пустая строка.
154 155 /// </summary>
155 156 public string ElementName {
156 157 get { return m_memberName; }
157 158 }
158 159
159 160 /// <summary>
160 161 /// Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ элСмСнта. Волько для элСмСнтов Ρ‚ΠΈΠΏΠ° <see cref="JSONElementType.Value"/>, для ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… <c>null</c>
161 162 /// </summary>
162 163 public object ElementValue {
163 164 get { return m_elementValue; }
164 165 }
165 166
166 167 /// <summary>
167 168 /// Π§ΠΈΡ‚Π°Π΅Ρ‚ ΡΠ»Π΅ΡŽΡƒΠ΄ΡƒΡ‰ΠΈΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ· ΠΏΠΎΡ‚ΠΎΠΊΠ°
168 169 /// </summary>
169 170 /// <returns><c>true</c> - опСрация чтСния ΠΏΡ€ΠΎΡˆΠ»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, <c>false</c> - ΠΊΠΎΠ½Π΅Ρ† Π΄Π°Π½Π½Ρ‹Ρ…</returns>
170 171 public bool Read() {
171 172 object tokenValue;
172 173 JsonTokenType tokenType;
173 174
174 175 m_memberName = String.Empty;
175 176
176 177 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
177 178 if(!m_context.Move(tokenType))
178 179 UnexpectedToken(tokenValue, tokenType);
179 180
180 181 switch (tokenType) {
181 182 case JsonTokenType.BeginObject:
182 183 m_stack.Push(m_context);
183 184 m_context = _objectContext;
184 185
185 186 m_elementValue = null;
186 187 m_memberContext = MemberContext.MemberName;
187 188 m_elementType = JSONElementType.BeginObject;
188 189 return true;
189 190 case JsonTokenType.EndObject:
190 191 if (m_stack.Count == 0)
191 192 UnexpectedToken(tokenValue, tokenType);
192 193 m_context = m_stack.Pop();
193 194
194 195 m_elementValue = null;
195 196 m_elementType = JSONElementType.EndObject;
196 197 return true;
197 198 case JsonTokenType.BeginArray:
198 199 m_stack.Push(m_context);
199 200 m_context = _arrayContext;
200 201
201 202 m_elementValue = null;
202 203 m_memberContext = MemberContext.MemberValue;
203 204 m_elementType = JSONElementType.BeginArray;
204 205 return true;
205 206 case JsonTokenType.EndArray:
206 207 if (m_stack.Count == 0)
207 208 UnexpectedToken(tokenValue, tokenType);
208 209 m_context = m_stack.Pop();
209 210
210 211 m_elementValue = null;
211 212 m_elementType = JSONElementType.EndArray;
212 213 return true;
213 214 case JsonTokenType.String:
214 215 if (m_memberContext == MemberContext.MemberName) {
215 216 m_memberName = (string)tokenValue;
216 217 break;
217 218 }
218 219 m_elementType = JSONElementType.Value;
219 220 m_elementValue = tokenValue;
220 221 return true;
221 222 case JsonTokenType.Number:
222 223 m_elementType = JSONElementType.Value;
223 224 m_elementValue = tokenValue;
224 225 return true;
225 226 case JsonTokenType.Literal:
226 227 m_elementType = JSONElementType.Value;
227 228 m_elementValue = ParseLiteral((string)tokenValue);
228 229 return true;
229 230 case JsonTokenType.NameSeparator:
230 231 m_memberContext = MemberContext.MemberValue;
231 232 break;
232 233 case JsonTokenType.ValueSeparator:
233 234 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
234 235 break;
235 236 default:
236 237 UnexpectedToken(tokenValue, tokenType);
237 238 break;
238 239 }
239 240 }
240 241 if (m_context.ElementContext != JSONElementContext.None)
241 242 throw new ParserException("Unexpedted end of data");
242 243
243 244 EOF = true;
244 245
245 246 return false;
246 247 }
247 248
248 249 object ParseLiteral(string literal) {
249 250 switch (literal) {
250 251 case "null":
251 252 return null;
252 253 case "false":
253 254 return false;
254 255 case "true":
255 256 return true;
256 257 default:
257 258 UnexpectedToken(literal, JsonTokenType.Literal);
258 259 return null; // avoid compliler error
259 260 }
260 261 }
261 262
262 263 void UnexpectedToken(object value, JsonTokenType tokenType) {
263 264 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
264 265 }
265 266
266 267
267 268 /// <summary>
268 269 /// ΠŸΡ€ΠΈΠ·Π½Π°ΠΊ ΠΊΠΎΠ½Ρ†Π° ΠΏΠΎΡ‚ΠΎΠΊΠ°
269 270 /// </summary>
270 271 public bool EOF {
271 272 get;
272 273 private set;
273 274 }
274 275
275 276 protected override void Dispose(bool disposing) {
276 277 if (disposing)
277 278 m_scanner.Dispose();
278 279 }
279 280
280 281 /// <summary>
281 282 /// ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ Π² ΠΊΠΎΠ½Π΅Ρ† Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.
282 283 /// </summary>
283 284 public void SeekElementEnd() {
284 285 var level = Level - 1;
285 286
286 287 Debug.Assert(level >= 0);
287 288
288 289 while (Level != level)
289 290 Read();
290 291 }
291 292 }
292 293
293 294 }
@@ -1,62 +1,62
1 1
2 2 using System.Xml;
3 3
4 namespace Implab.Formats.JSON {
4 namespace Implab.Xml {
5 5 /// <summary>
6 6 /// Набор Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² для <see cref="JSONXmlReader"/>, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ процСссом
7 7 /// ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ†ΠΈΠΈ <c>JSON</c> Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
8 8 /// </summary>
9 public class JSONXmlReaderOptions {
9 public class JsonXmlReaderOptions {
10 10 /// <summary>
11 11 /// ΠŸΡ€ΠΎΡΡ‚Ρ€Π°Π½ΡΡ‚Π²ΠΎ ΠΈΠΌΠ΅Π½ Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°Ρ‚ΡŒΡΡ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹Π΅ элСмСнты Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
12 12 /// </summary>
13 public string NamespaceURI {
13 public string NamespaceUri {
14 14 get;
15 15 set;
16 16 }
17 17
18 18 /// <summary>
19 19 /// Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ массивы ΠΊΠ°ΠΊ мноТСствСнныС элСмСнты (ΡƒΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности), ΠΈΠ½Π°Ρ‡Π΅ массив
20 20 /// прСдставляСтся Π² Π²ΠΈΠ΄Π΅ ΡƒΠ·Π»Π°, Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌΠΈ элСмСнтами ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΡΠ²Π»ΡΡŽΡ‚ΡΡ элСмСнты массива, ΠΈΠΌΠ΅Π½Π° Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… элСмСнтов
21 21 /// ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ свойством <see cref="ArrayItemName"/>. По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>false</c>.
22 22 /// </summary>
23 23 public bool FlattenArrays {
24 24 get;
25 25 set;
26 26 }
27 27
28 28 /// <summary>
29 29 /// ΠŸΡ€Π΅Ρ„ΠΈΠΊΡ, для ΡƒΠ·Π»ΠΎΠ² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
30 30 /// </summary>
31 31 public string NodesPrefix {
32 32 get;
33 33 set;
34 34 }
35 35
36 36 /// <summary>
37 37 /// Имя ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ элСмСнта Π² xml Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅
38 38 /// </summary>
39 39 public string RootName {
40 40 get;
41 41 set;
42 42 }
43 43
44 44 /// <summary>
45 45 /// Имя элСмСнта для массивов, Ссли Π½Π΅ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π° опция <see cref="FlattenArrays"/>.
46 46 /// По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ <c>item</c>.
47 47 /// </summary>
48 48 public string ArrayItemName {
49 49 get;
50 50 set;
51 51 }
52 52
53 53 /// <summary>
54 54 /// Π’Π°Π±Π»ΠΈΡ†Π° Π°Ρ‚ΠΎΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… строк для построСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
55 55 /// </summary>
56 56 public XmlNameTable NameTable {
57 57 get;
58 58 set;
59 59 }
60 60
61 61 }
62 62 }
@@ -1,276 +1,281
1 1 ο»Ώ<?xml version="1.0" encoding="utf-8"?>
2 2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 7 <OutputType>Library</OutputType>
8 8 <RootNamespace>Implab</RootNamespace>
9 9 <AssemblyName>Implab</AssemblyName>
10 10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11 11 </PropertyGroup>
12 12 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
13 13 <DebugSymbols>true</DebugSymbols>
14 14 <DebugType>full</DebugType>
15 15 <Optimize>false</Optimize>
16 16 <OutputPath>bin\Debug</OutputPath>
17 17 <DefineConstants>TRACE;DEBUG;</DefineConstants>
18 18 <ErrorReport>prompt</ErrorReport>
19 19 <WarningLevel>4</WarningLevel>
20 20 <ConsolePause>false</ConsolePause>
21 21 <RunCodeAnalysis>true</RunCodeAnalysis>
22 22 </PropertyGroup>
23 23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24 24 <DebugType>full</DebugType>
25 25 <Optimize>true</Optimize>
26 26 <OutputPath>bin\Release</OutputPath>
27 27 <ErrorReport>prompt</ErrorReport>
28 28 <WarningLevel>4</WarningLevel>
29 29 <ConsolePause>false</ConsolePause>
30 30 </PropertyGroup>
31 31 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
32 32 <DebugSymbols>true</DebugSymbols>
33 33 <DebugType>full</DebugType>
34 34 <Optimize>false</Optimize>
35 35 <OutputPath>bin\Debug</OutputPath>
36 36 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
37 37 <ErrorReport>prompt</ErrorReport>
38 38 <WarningLevel>4</WarningLevel>
39 39 <RunCodeAnalysis>true</RunCodeAnalysis>
40 40 <ConsolePause>false</ConsolePause>
41 41 </PropertyGroup>
42 42 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
43 43 <Optimize>true</Optimize>
44 44 <OutputPath>bin\Release</OutputPath>
45 45 <ErrorReport>prompt</ErrorReport>
46 46 <WarningLevel>4</WarningLevel>
47 47 <ConsolePause>false</ConsolePause>
48 48 <DefineConstants>NET_4_5</DefineConstants>
49 49 </PropertyGroup>
50 50 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
51 51 <DebugSymbols>true</DebugSymbols>
52 52 <DebugType>full</DebugType>
53 53 <Optimize>false</Optimize>
54 54 <OutputPath>bin\Debug</OutputPath>
55 55 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
56 56 <ErrorReport>prompt</ErrorReport>
57 57 <WarningLevel>4</WarningLevel>
58 58 <RunCodeAnalysis>true</RunCodeAnalysis>
59 59 <ConsolePause>false</ConsolePause>
60 60 </PropertyGroup>
61 61 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
62 62 <Optimize>true</Optimize>
63 63 <OutputPath>bin\Release</OutputPath>
64 64 <DefineConstants>NET_4_5;MONO;</DefineConstants>
65 65 <ErrorReport>prompt</ErrorReport>
66 66 <WarningLevel>4</WarningLevel>
67 67 <ConsolePause>false</ConsolePause>
68 68 </PropertyGroup>
69 69 <ItemGroup>
70 70 <Reference Include="System" />
71 71 <Reference Include="System.Xml" />
72 72 <Reference Include="mscorlib" />
73 73 </ItemGroup>
74 74 <ItemGroup>
75 75 <Compile Include="Components\StateChangeEventArgs.cs" />
76 76 <Compile Include="CustomEqualityComparer.cs" />
77 77 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
78 78 <Compile Include="Diagnostics\LogChannel.cs" />
79 79 <Compile Include="Diagnostics\LogicalOperation.cs" />
80 80 <Compile Include="Diagnostics\TextFileListener.cs" />
81 81 <Compile Include="Diagnostics\Trace.cs" />
82 82 <Compile Include="Diagnostics\TraceLog.cs" />
83 83 <Compile Include="Diagnostics\TraceEvent.cs" />
84 84 <Compile Include="Diagnostics\TraceEventType.cs" />
85 85 <Compile Include="Diagnostics\TraceSourceAttribute.cs" />
86 86 <Compile Include="ICancellable.cs" />
87 87 <Compile Include="IProgressHandler.cs" />
88 88 <Compile Include="IProgressNotifier.cs" />
89 89 <Compile Include="IPromiseT.cs" />
90 90 <Compile Include="IPromise.cs" />
91 91 <Compile Include="IServiceLocator.cs" />
92 92 <Compile Include="ITaskController.cs" />
93 93 <Compile Include="Parallels\DispatchPool.cs" />
94 94 <Compile Include="Parallels\ArrayTraits.cs" />
95 95 <Compile Include="Parallels\MTQueue.cs" />
96 96 <Compile Include="Parallels\WorkerPool.cs" />
97 97 <Compile Include="ProgressInitEventArgs.cs" />
98 98 <Compile Include="Properties\AssemblyInfo.cs" />
99 99 <Compile Include="Parallels\AsyncPool.cs" />
100 100 <Compile Include="Safe.cs" />
101 101 <Compile Include="SyncContextPromise.cs" />
102 102 <Compile Include="ValueEventArgs.cs" />
103 103 <Compile Include="PromiseExtensions.cs" />
104 104 <Compile Include="SyncContextPromiseT.cs" />
105 105 <Compile Include="Diagnostics\OperationContext.cs" />
106 106 <Compile Include="Diagnostics\TraceContext.cs" />
107 107 <Compile Include="Diagnostics\LogEventArgs.cs" />
108 108 <Compile Include="Diagnostics\LogEventArgsT.cs" />
109 109 <Compile Include="Diagnostics\Extensions.cs" />
110 110 <Compile Include="PromiseEventType.cs" />
111 111 <Compile Include="Parallels\AsyncQueue.cs" />
112 112 <Compile Include="PromiseT.cs" />
113 113 <Compile Include="IDeferred.cs" />
114 114 <Compile Include="IDeferredT.cs" />
115 115 <Compile Include="Promise.cs" />
116 116 <Compile Include="PromiseTransientException.cs" />
117 117 <Compile Include="Parallels\Signal.cs" />
118 118 <Compile Include="Parallels\SharedLock.cs" />
119 119 <Compile Include="Diagnostics\ILogWriter.cs" />
120 120 <Compile Include="Diagnostics\ListenerBase.cs" />
121 121 <Compile Include="Parallels\BlockingQueue.cs" />
122 122 <Compile Include="AbstractEvent.cs" />
123 123 <Compile Include="AbstractPromise.cs" />
124 124 <Compile Include="AbstractPromiseT.cs" />
125 125 <Compile Include="FuncTask.cs" />
126 126 <Compile Include="FuncTaskBase.cs" />
127 127 <Compile Include="FuncTaskT.cs" />
128 128 <Compile Include="ActionChainTaskBase.cs" />
129 129 <Compile Include="ActionChainTask.cs" />
130 130 <Compile Include="ActionChainTaskT.cs" />
131 131 <Compile Include="FuncChainTaskBase.cs" />
132 132 <Compile Include="FuncChainTask.cs" />
133 133 <Compile Include="FuncChainTaskT.cs" />
134 134 <Compile Include="ActionTaskBase.cs" />
135 135 <Compile Include="ActionTask.cs" />
136 136 <Compile Include="ActionTaskT.cs" />
137 137 <Compile Include="ICancellationToken.cs" />
138 138 <Compile Include="SuccessPromise.cs" />
139 139 <Compile Include="SuccessPromiseT.cs" />
140 140 <Compile Include="PromiseAwaiterT.cs" />
141 141 <Compile Include="PromiseAwaiter.cs" />
142 142 <Compile Include="Components\ComponentContainer.cs" />
143 143 <Compile Include="Components\Disposable.cs" />
144 144 <Compile Include="Components\DisposablePool.cs" />
145 145 <Compile Include="Components\ObjectPool.cs" />
146 146 <Compile Include="Components\ServiceLocator.cs" />
147 147 <Compile Include="Components\IInitializable.cs" />
148 148 <Compile Include="TaskController.cs" />
149 149 <Compile Include="Components\App.cs" />
150 150 <Compile Include="Components\IRunnable.cs" />
151 151 <Compile Include="Components\ExecutionState.cs" />
152 152 <Compile Include="Components\RunnableComponent.cs" />
153 153 <Compile Include="Components\IFactory.cs" />
154 154 <Compile Include="Automaton\IAlphabet.cs" />
155 155 <Compile Include="Automaton\ParserException.cs" />
156 156 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
157 157 <Compile Include="Automaton\IAlphabetBuilder.cs" />
158 158 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
159 159 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
160 160 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
161 161 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
162 162 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
163 163 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
164 164 <Compile Include="Automaton\RegularExpressions\Token.cs" />
165 165 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
166 166 <Compile Include="Automaton\AutomatonTransition.cs" />
167 167 <Compile Include="Formats\JSON\JSONElementContext.cs" />
168 168 <Compile Include="Formats\JSON\JSONElementType.cs" />
169 169 <Compile Include="Formats\JSON\JSONGrammar.cs" />
170 170 <Compile Include="Formats\JSON\JSONParser.cs" />
171 171 <Compile Include="Formats\JSON\JSONScanner.cs" />
172 172 <Compile Include="Formats\JSON\JsonTokenType.cs" />
173 173 <Compile Include="Formats\JSON\JSONWriter.cs" />
174 174 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
175 175 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
176 176 <Compile Include="Formats\JSON\StringTranslator.cs" />
177 177 <Compile Include="Automaton\MapAlphabet.cs" />
178 178 <Compile Include="Formats\CharAlphabet.cs" />
179 179 <Compile Include="Formats\ByteAlphabet.cs" />
180 180 <Compile Include="Automaton\IDFATable.cs" />
181 181 <Compile Include="Automaton\IDFATableBuilder.cs" />
182 182 <Compile Include="Automaton\DFATable.cs" />
183 183 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
184 184 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
185 185 <Compile Include="Formats\TextScanner.cs" />
186 186 <Compile Include="Formats\StringScanner.cs" />
187 187 <Compile Include="Formats\ReaderScanner.cs" />
188 188 <Compile Include="Formats\ScannerContext.cs" />
189 189 <Compile Include="Formats\Grammar.cs" />
190 190 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
191 191 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
192 192 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
193 193 <Compile Include="Automaton\AutomatonConst.cs" />
194 194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
195 195 <Compile Include="Components\LazyAndWeak.cs" />
196 196 <Compile Include="AbstractTask.cs" />
197 197 <Compile Include="AbstractTaskT.cs" />
198 198 <Compile Include="FailedPromise.cs" />
199 199 <Compile Include="FailedPromiseT.cs" />
200 200 <Compile Include="Components\PollingComponent.cs" />
201 <Compile Include="Xml\JsonXmlReader.cs" />
202 <Compile Include="Xml\JsonXmlReaderOptions.cs" />
203 <Compile Include="Xml\JsonXmlReaderPosition.cs" />
204 <Compile Include="Xml\XmlSimpleAttribute.cs" />
205 <Compile Include="Xml\XmlNameContext.cs" />
201 206 </ItemGroup>
202 207 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
203 208 <ItemGroup />
204 209 <ProjectExtensions>
205 210 <MonoDevelop>
206 211 <Properties>
207 212 <Policies>
208 213 <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInProperties="False" NewLinesForBracesInAccessors="False" NewLinesForBracesInAnonymousMethods="False" NewLinesForBracesInControlBlocks="False" NewLinesForBracesInAnonymousTypes="False" NewLinesForBracesInObjectCollectionArrayInitializers="False" NewLinesForBracesInLambdaExpressionBody="False" NewLineForElse="False" NewLineForCatch="False" NewLineForFinally="False" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" SpacingAfterMethodDeclarationName="True" SpaceAfterMethodCallName="True" SpaceBeforeOpenSquareBracket="True" SpaceBeforeColonInBaseTypeDeclaration="True" scope="text/x-csharp" />
209 214 <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" TabsToSpaces="True" EolMarker="Unix" scope="text/x-csharp" />
210 215 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
211 216 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="application/xml" />
212 217 <XmlFormattingPolicy scope="application/xml">
213 <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString="&#x9;" AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString="&#x9;" WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
218 <DefaultFormat OmitXmlDeclaration="False" NewLineChars="&#xA;" IndentContent="True" ContentIndentString=" " AttributesInNewLine="False" MaxAttributesPerLine="10" AttributesIndentString=" " WrapAttributes="False" AlignAttributes="False" AlignAttributeValues="False" QuoteChar="&quot;" SpacesBeforeAssignment="0" SpacesAfterAssignment="0" EmptyLinesBeforeStart="0" EmptyLinesAfterStart="0" EmptyLinesBeforeEnd="0" EmptyLinesAfterEnd="0" />
214 219 </XmlFormattingPolicy>
215 220 <TextStylePolicy FileWidth="120" TabWidth="4" TabsToSpaces="False" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" scope="text/plain" />
216 221 <NameConventionPolicy>
217 222 <Rules>
218 223 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
219 224 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
220 225 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
221 226 <RequiredPrefixes>
222 227 <String>I</String>
223 228 </RequiredPrefixes>
224 229 </NamingRule>
225 230 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
226 231 <RequiredSuffixes>
227 232 <String>Attribute</String>
228 233 </RequiredSuffixes>
229 234 </NamingRule>
230 235 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
231 236 <RequiredSuffixes>
232 237 <String>EventArgs</String>
233 238 </RequiredSuffixes>
234 239 </NamingRule>
235 240 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
236 241 <RequiredSuffixes>
237 242 <String>Exception</String>
238 243 </RequiredSuffixes>
239 244 </NamingRule>
240 245 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
241 246 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
242 247 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
243 248 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
244 249 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
245 250 <RequiredPrefixes>
246 251 <String>m_</String>
247 252 </RequiredPrefixes>
248 253 </NamingRule>
249 254 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
250 255 <RequiredPrefixes>
251 256 <String>_</String>
252 257 </RequiredPrefixes>
253 258 </NamingRule>
254 259 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
255 260 <RequiredPrefixes>
256 261 <String>m_</String>
257 262 </RequiredPrefixes>
258 263 </NamingRule>
259 264 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
260 265 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
261 266 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
262 267 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
263 268 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
264 269 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
265 270 <RequiredPrefixes>
266 271 <String>T</String>
267 272 </RequiredPrefixes>
268 273 </NamingRule>
269 274 </Rules>
270 275 </NameConventionPolicy>
271 276 </Policies>
272 277 </Properties>
273 278 </MonoDevelop>
274 279 </ProjectExtensions>
275 280 <ItemGroup />
276 281 </Project> No newline at end of file
@@ -1,631 +1,623
1 1 using System.Threading;
2 2 using System.Collections.Generic;
3 3 using System;
4 4 using System.Collections;
5 5 using System.Diagnostics;
6 6
7 7 namespace Implab.Parallels {
8 8 public class AsyncQueue<T> : IEnumerable<T> {
9 9 class Chunk {
10 10 public Chunk next;
11 11
12 12 int m_low;
13 13 int m_hi;
14 14 int m_alloc;
15 15 readonly int m_size;
16 16 readonly T[] m_data;
17 17
18 18 public Chunk(int size) {
19 19 m_size = size;
20 20 m_data = new T[size];
21 21 }
22 22
23 23 public Chunk(int size, T value) {
24 24 m_size = size;
25 25 m_hi = 1;
26 26 m_alloc = 1;
27 27 m_data = new T[size];
28 28 m_data[0] = value;
29 29 }
30 30
31 31 public Chunk(int size, T[] data, int offset, int length, int alloc) {
32 32 m_size = size;
33 33 m_hi = length;
34 34 m_alloc = alloc;
35 35 m_data = new T[size];
36 36 Array.Copy(data, offset, m_data, 0, length);
37 37 }
38 38
39 39 public int Low {
40 40 get { return m_low; }
41 41 }
42 42
43 43 public int Hi {
44 44 get { return m_hi; }
45 45 }
46 46
47 47 public int Size {
48 48 get { return m_size; }
49 49 }
50 50
51 51 public bool TryEnqueue(T value, out bool extend) {
52 52 var alloc = Interlocked.Increment(ref m_alloc) - 1;
53 53
54 54 if (alloc >= m_size) {
55 55 extend = alloc == m_size;
56 56 return false;
57 57 }
58 58
59 59 extend = false;
60 60 m_data[alloc] = value;
61 61
62 62 while (alloc != Interlocked.CompareExchange(ref m_hi, alloc + 1, alloc)) {
63 63 // spin wait for commit
64 64 }
65 65 return true;
66 66 }
67 67
68 68 /// <summary>
69 69 /// Prevents from allocating new space in the chunk and waits for all write operations to complete
70 70 /// </summary>
71 71 public void Commit() {
72 72 var actual = Math.Min(Interlocked.Exchange(ref m_alloc, m_size + 1), m_size);
73 73
74 74 while (m_hi != actual)
75 75 Thread.MemoryBarrier();
76 76 }
77 77
78 78 public bool TryDequeue(out T value, out bool recycle) {
79 79 int low;
80 80 do {
81 81 low = m_low;
82 82 if (low >= m_hi) {
83 83 value = default(T);
84 84 recycle = (low == m_size);
85 85 return false;
86 86 }
87 87 } while(low != Interlocked.CompareExchange(ref m_low, low + 1, low));
88 88
89 89 recycle = (low == m_size - 1);
90 90 value = m_data[low];
91 91
92 92 return true;
93 93 }
94 94
95 95 public bool TryEnqueueBatch(T[] batch, int offset, int length, out int enqueued, out bool extend) {
96 96 //int alloc;
97 97 //int allocSize;
98 98
99 99 var alloc = Interlocked.Add(ref m_alloc, length) - length;
100 100 if (alloc > m_size) {
101 101 // the chunk is full and someone already
102 102 // creating the new one
103 103 enqueued = 0; // nothing was added
104 104 extend = false; // the caller shouldn't try to extend the queue
105 105 return false; // nothing was added
106 106 }
107 107
108 108 enqueued = Math.Min(m_size - alloc, length);
109 109 extend = length > enqueued;
110 110
111 111 if (enqueued == 0)
112 112 return false;
113 113
114 114
115 115 Array.Copy(batch, offset, m_data, alloc, enqueued);
116 116
117 117 while (alloc != Interlocked.CompareExchange(ref m_hi, alloc + enqueued, alloc)) {
118 118 // spin wait for commit
119 119 }
120 120
121 121 return true;
122 122 }
123 123
124 124 public bool TryDequeueBatch(T[] buffer, int offset, int length,out int dequeued, out bool recycle) {
125 125 int low, hi, batchSize;
126 126
127 127 do {
128 128 low = m_low;
129 129 hi = m_hi;
130 130 if (low >= hi) {
131 131 dequeued = 0;
132 132 recycle = (low == m_size); // recycling could be restarted and we need to signal again
133 133 return false;
134 134 }
135 135 batchSize = Math.Min(hi - low, length);
136 136 } while(low != Interlocked.CompareExchange(ref m_low, low + batchSize, low));
137 137
138 138 recycle = (low == m_size - batchSize);
139 139 dequeued = batchSize;
140 140
141 141 Array.Copy(m_data, low, buffer, offset, batchSize);
142 142
143 143 return true;
144 144 }
145 145
146 146 public T GetAt(int pos) {
147 147 return m_data[pos];
148 148 }
149 149 }
150 150
151 151 public const int DEFAULT_CHUNK_SIZE = 32;
152 152 public const int MAX_CHUNK_SIZE = 262144;
153 153
154 154 Chunk m_first;
155 155 Chunk m_last;
156 156
157 157 /// <summary>
158 158 /// Adds the specified value to the queue.
159 159 /// </summary>
160 160 /// <param name="value">Tha value which will be added to the queue.</param>
161 161 public virtual void Enqueue(T value) {
162 162 var last = m_last;
163 163 // spin wait to the new chunk
164 164 bool extend = true;
165 165 while (last == null || !last.TryEnqueue(value, out extend)) {
166 166 // try to extend queue
167 167 if (extend || last == null) {
168 168 var chunk = new Chunk(DEFAULT_CHUNK_SIZE, value);
169 169 if (EnqueueChunk(last, chunk))
170 170 break; // success! exit!
171 171 last = m_last;
172 172 } else {
173 173 while (last == m_last) {
174 174 Thread.MemoryBarrier();
175 175 }
176 176 last = m_last;
177 177 }
178 178 }
179 179 }
180 180
181 181 /// <summary>
182 182 /// Adds the specified data to the queue.
183 183 /// </summary>
184 184 /// <param name="data">The buffer which contains the data to be enqueued.</param>
185 185 /// <param name="offset">The offset of the data in the buffer.</param>
186 186 /// <param name="length">The size of the data to read from the buffer.</param>
187 187 public virtual void EnqueueRange(T[] data, int offset, int length) {
188 188 if (data == null)
189 189 throw new ArgumentNullException("data");
190 190 if (length == 0)
191 191 return;
192 192 if (offset < 0)
193 193 throw new ArgumentOutOfRangeException("offset");
194 194 if (length < 1 || offset + length > data.Length)
195 195 throw new ArgumentOutOfRangeException("length");
196 196
197 197 var last = m_last;
198 198
199 199 bool extend;
200 200 int enqueued;
201 201
202 202 while (length > 0) {
203 203 extend = true;
204 204 if (last != null && last.TryEnqueueBatch(data, offset, length, out enqueued, out extend)) {
205 205 length -= enqueued;
206 206 offset += enqueued;
207 207 }
208 208
209 209 if (extend) {
210 210 // there was no enough space in the chunk
211 211 // or there was no chunks in the queue
212 212
213 213 while (length > 0) {
214 214
215 215 var size = Math.Min(length, MAX_CHUNK_SIZE);
216 216
217 217 var chunk = new Chunk(
218 218 Math.Max(size, DEFAULT_CHUNK_SIZE),
219 219 data,
220 220 offset,
221 221 size,
222 222 length // length >= size
223 223 );
224 224
225 225 if (!EnqueueChunk(last, chunk)) {
226 226 // looks like the queue has been updated then proceed from the beginning
227 227 last = m_last;
228 228 break;
229 229 }
230 230
231 231 // we have successfully added the new chunk
232 232 last = chunk;
233 233 length -= size;
234 234 offset += size;
235 235 }
236 236 } else {
237 237 // we don't need to extend the queue, if we successfully enqueued data
238 238 if (length == 0)
239 239 break;
240 240
241 241 // if we need to wait while someone is extending the queue
242 242 // spinwait
243 243 while (last == m_last) {
244 244 Thread.MemoryBarrier();
245 245 }
246 246
247 247 last = m_last;
248 248 }
249 249 }
250 250 }
251 251
252 252 /// <summary>
253 253 /// Tries to retrieve the first element from the queue.
254 254 /// </summary>
255 255 /// <returns><c>true</c>, if element is dequeued, <c>false</c> otherwise.</returns>
256 256 /// <param name="value">The value of the dequeued element.</param>
257 257 public bool TryDequeue(out T value) {
258 258 var chunk = m_first;
259 259 bool recycle;
260 260 while (chunk != null) {
261 261
262 262 var result = chunk.TryDequeue(out value, out recycle);
263 263
264 264 if (recycle) // this chunk is waste
265 265 RecycleFirstChunk(chunk);
266 266 else
267 267 return result; // this chunk is usable and returned actual result
268 268
269 269 if (result) // this chunk is waste but the true result is always actual
270 270 return true;
271 271
272 272 // try again
273 273 chunk = m_first;
274 274 }
275 275
276 276 // the queue is empty
277 277 value = default(T);
278 278 return false;
279 279 }
280 280
281 281 /// <summary>
282 282 /// Tries to dequeue the specified amount of data from the queue.
283 283 /// </summary>
284 284 /// <returns><c>true</c>, if data was deuqueued, <c>false</c> otherwise.</returns>
285 285 /// <param name="buffer">The buffer to which the data will be written.</param>
286 286 /// <param name="offset">The offset in the buffer at which the data will be written.</param>
287 287 /// <param name="length">The maximum amount of data to be retrieved.</param>
288 288 /// <param name="dequeued">The actual amout of the retrieved data.</param>
289 289 public bool TryDequeueRange(T[] buffer, int offset, int length, out int dequeued) {
290 290 if (buffer == null)
291 291 throw new ArgumentNullException("buffer");
292 292 if (offset < 0)
293 293 throw new ArgumentOutOfRangeException("offset");
294 294 if (length < 1 || offset + length > buffer.Length)
295 295 throw new ArgumentOutOfRangeException("length");
296 296
297 297 var chunk = m_first;
298 298 bool recycle;
299 299 dequeued = 0;
300 300 while (chunk != null) {
301 301
302 302 int actual;
303 303 if (chunk.TryDequeueBatch(buffer, offset, length, out actual, out recycle)) {
304 304 offset += actual;
305 305 length -= actual;
306 306 dequeued += actual;
307 307 }
308 308
309 309 if (recycle) // this chunk is waste
310 310 RecycleFirstChunk(chunk);
311 311 else if (actual == 0)
312 312 break; // the chunk is usable, but doesn't contain any data (it's the last chunk in the queue)
313 313
314 314 if (length == 0)
315 315 return true;
316 316
317 317 // we still may dequeue something
318 318 // try again
319 319 chunk = m_first;
320 320 }
321 321
322 322 return dequeued != 0;
323 323 }
324 324
325 325 /// <summary>
326 326 /// Tries to dequeue all remaining data in the first chunk.
327 327 /// </summary>
328 328 /// <returns><c>true</c>, if data was dequeued, <c>false</c> otherwise.</returns>
329 329 /// <param name="buffer">The buffer to which the data will be written.</param>
330 330 /// <param name="offset">The offset in the buffer at which the data will be written.</param>
331 331 /// <param name="length">Tha maximum amount of the data to be dequeued.</param>
332 332 /// <param name="dequeued">The actual amount of the dequeued data.</param>
333 333 public bool TryDequeueChunk(T[] buffer, int offset, int length, out int dequeued) {
334 334 if (buffer == null)
335 335 throw new ArgumentNullException("buffer");
336 336 if (offset < 0)
337 337 throw new ArgumentOutOfRangeException("offset");
338 338 if (length < 1 || offset + length > buffer.Length)
339 339 throw new ArgumentOutOfRangeException("length");
340 340
341 341 var chunk = m_first;
342 342 bool recycle;
343 343 dequeued = 0;
344 344
345 345 while (chunk != null) {
346 346
347 347 int actual;
348 348 if (chunk.TryDequeueBatch(buffer, offset, length, out actual, out recycle)) {
349 349 dequeued = actual;
350 350 }
351 351
352 352 if (recycle) // this chunk is waste
353 353 RecycleFirstChunk(chunk);
354 354
355 355 // if we have dequeued any data, then return
356 356 if (dequeued != 0)
357 357 return true;
358 358
359 359 // we still may dequeue something
360 360 // try again
361 361 chunk = m_first;
362 362 }
363 363
364 364 return false;
365 365 }
366 366
367 367 bool EnqueueChunk(Chunk last, Chunk chunk) {
368 368 if (Interlocked.CompareExchange(ref m_last, chunk, last) != last)
369 369 return false;
370 370
371 371 if (last != null)
372 372 last.next = chunk;
373 373 else {
374 374 m_first = chunk;
375 375 }
376 376 return true;
377 377 }
378 378
379 379 void RecycleFirstChunk(Chunk first) {
380 380 var next = first.next;
381 381
382 382 if (first != Interlocked.CompareExchange(ref m_first, next, first))
383 383 return;
384 384
385 385 if (next == null) {
386 386
387 387 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
388 /*while (first.next == null)
389 Thread.MemoryBarrier();*/
390 388
391 389 // race
392 390 // someone already updated the tail, restore the pointer to the queue head
393 391 m_first = first;
394 392 }
395 393 // the tail is updated
396 394 }
397
398 // we need to update the head
399 //Interlocked.CompareExchange(ref m_first, next, first);
400 // if the head is already updated then give up
401 //return;
402
403 395 }
404 396
405 397 public void Clear() {
406 398 // start the new queue
407 399 var chunk = new Chunk(DEFAULT_CHUNK_SIZE);
408 400
409 401 do {
410 402 Thread.MemoryBarrier();
411 403 var first = m_first;
412 404 var last = m_last;
413 405
414 406 if (last == null) // nothing to clear
415 407 return;
416 408
417 409 if (first == null || (first.next == null && first != last)) // inconcistency
418 410 continue;
419 411
420 412 // here we will create inconsistency which will force others to spin
421 413 // and prevent from fetching. chunk.next = null
422 414 if (first != Interlocked.CompareExchange(ref m_first, chunk, first))
423 415 continue;// inconsistent
424 416
425 417 m_last = chunk;
426 418
427 419 return;
428 420
429 421 } while(true);
430 422 }
431 423
432 424 public T[] Drain() {
433 425 // start the new queue
434 426 var chunk = new Chunk(DEFAULT_CHUNK_SIZE);
435 427
436 428 do {
437 429 Thread.MemoryBarrier();
438 430 var first = m_first;
439 431 var last = m_last;
440 432
441 433 if (last == null)
442 434 return new T[0];
443 435
444 436 if (first == null || (first.next == null && first != last))
445 437 continue;
446 438
447 439 // here we will create inconsistency which will force others to spin
448 440 // and prevent from fetching. chunk.next = null
449 441 if (first != Interlocked.CompareExchange(ref m_first, chunk, first))
450 442 continue;// inconsistent
451 443
452 444 last = Interlocked.Exchange(ref m_last, chunk);
453 445
454 446 return ReadChunks(first, last);
455 447
456 448 } while(true);
457 449 }
458 450
459 451 static T[] ReadChunks(Chunk chunk, object last) {
460 452 var result = new List<T>();
461 453 var buffer = new T[DEFAULT_CHUNK_SIZE];
462 454 int actual;
463 455 bool recycle;
464 456 while (chunk != null) {
465 457 // ensure all write operations on the chunk are complete
466 458 chunk.Commit();
467 459
468 460 // we need to read the chunk using this way
469 461 // since some client still may completing the dequeue
470 462 // operation, such clients most likely won't get results
471 463 while (chunk.TryDequeueBatch(buffer, 0, buffer.Length, out actual, out recycle))
472 464 result.AddRange(new ArraySegmentCollection(buffer, 0, actual));
473 465
474 466 if (chunk == last) {
475 467 chunk = null;
476 468 } else {
477 469 while (chunk.next == null)
478 470 Thread.MemoryBarrier();
479 471 chunk = chunk.next;
480 472 }
481 473 }
482 474
483 475 return result.ToArray();
484 476 }
485 477
486 478 struct ArraySegmentCollection : ICollection<T> {
487 479 readonly T[] m_data;
488 480 readonly int m_offset;
489 481 readonly int m_length;
490 482
491 483 public ArraySegmentCollection(T[] data, int offset, int length) {
492 484 m_data = data;
493 485 m_offset = offset;
494 486 m_length = length;
495 487 }
496 488
497 489 #region ICollection implementation
498 490
499 491 public void Add(T item) {
500 492 throw new NotSupportedException();
501 493 }
502 494
503 495 public void Clear() {
504 496 throw new NotSupportedException();
505 497 }
506 498
507 499 public bool Contains(T item) {
508 500 return false;
509 501 }
510 502
511 503 public void CopyTo(T[] array, int arrayIndex) {
512 504 Array.Copy(m_data,m_offset,array,arrayIndex, m_length);
513 505 }
514 506
515 507 public bool Remove(T item) {
516 508 throw new NotSupportedException();
517 509 }
518 510
519 511 public int Count {
520 512 get {
521 513 return m_length;
522 514 }
523 515 }
524 516
525 517 public bool IsReadOnly {
526 518 get {
527 519 return true;
528 520 }
529 521 }
530 522
531 523 #endregion
532 524
533 525 #region IEnumerable implementation
534 526
535 527 public IEnumerator<T> GetEnumerator() {
536 528 for (int i = m_offset; i < m_length + m_offset; i++)
537 529 yield return m_data[i];
538 530 }
539 531
540 532 #endregion
541 533
542 534 #region IEnumerable implementation
543 535
544 536 IEnumerator IEnumerable.GetEnumerator() {
545 537 return GetEnumerator();
546 538 }
547 539
548 540 #endregion
549 541 }
550 542
551 543 #region IEnumerable implementation
552 544
553 545 class Enumerator : IEnumerator<T> {
554 546 Chunk m_current;
555 547 int m_pos = -1;
556 548
557 549 public Enumerator(Chunk fisrt) {
558 550 m_current = fisrt;
559 551 }
560 552
561 553 #region IEnumerator implementation
562 554
563 555 public bool MoveNext() {
564 556 if (m_current == null)
565 557 return false;
566 558
567 559 if (m_pos == -1)
568 560 m_pos = m_current.Low;
569 561 else
570 562 m_pos++;
571 563
572 564 if (m_pos == m_current.Hi) {
573 565
574 566 m_current = m_pos == m_current.Size ? m_current.next : null;
575 567
576 568 m_pos = 0;
577 569
578 570 if (m_current == null)
579 571 return false;
580 572 }
581 573
582 574 return true;
583 575 }
584 576
585 577 public void Reset() {
586 578 throw new NotSupportedException();
587 579 }
588 580
589 581 object IEnumerator.Current {
590 582 get {
591 583 return Current;
592 584 }
593 585 }
594 586
595 587 #endregion
596 588
597 589 #region IDisposable implementation
598 590
599 591 public void Dispose() {
600 592 }
601 593
602 594 #endregion
603 595
604 596 #region IEnumerator implementation
605 597
606 598 public T Current {
607 599 get {
608 600 if (m_pos == -1 || m_current == null)
609 601 throw new InvalidOperationException();
610 602 return m_current.GetAt(m_pos);
611 603 }
612 604 }
613 605
614 606 #endregion
615 607 }
616 608
617 609 public IEnumerator<T> GetEnumerator() {
618 610 return new Enumerator(m_first);
619 611 }
620 612
621 613 #endregion
622 614
623 615 #region IEnumerable implementation
624 616
625 617 IEnumerator IEnumerable.GetEnumerator() {
626 618 return GetEnumerator();
627 619 }
628 620
629 621 #endregion
630 622 }
631 623 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now