##// END OF EJS Templates
Prerelease version of RunnableComponent...
cin -
r251:7c7e9ad6fe4a v3
parent child
Show More
@@ -0,0 +1,14
1 namespace Implab.Messaging {
2 public interface ISession {
3 /// <summary>
4 /// Starts message consumers, call this method after all adapters are ready
5 /// </summary>
6 void Start();
7
8 /// <summary>
9 /// Stops message consumers
10 /// </summary>
11 void Stop();
12
13 }
14 } No newline at end of file
@@ -0,0 +1,70
1 using System;
2 using System.Threading.Tasks;
3
4 namespace Implab {
5 public static class TaskHelpers {
6
7 public static async Task Then(this Task that, Action fulfilled, Action<Exception> rejected) {
8 Safe.ArgumentNotNull(that, nameof(that));
9 if (rejected != null) {
10 try {
11 await that;
12 } catch (Exception e) {
13 rejected(e);
14 return;
15 }
16 } else {
17 await that;
18 }
19
20 if (fulfilled != null)
21 fulfilled();
22 }
23
24 public static async Task Then(this Task that, Action fulfilled) {
25 Safe.ArgumentNotNull(that, nameof(that));
26 await that;
27 if (fulfilled != null)
28 fulfilled();
29 }
30
31 public static async Task Then(this Task that, Func<Task> fulfilled) {
32 Safe.ArgumentNotNull(that, nameof(that));
33 await that;
34 if (fulfilled != null)
35 await fulfilled();
36 }
37
38 public static async Task Finally(this Task that, Action handler) {
39 Safe.ArgumentNotNull(that, nameof(that));
40 try {
41 await that;
42 } finally {
43 if (handler != null)
44 handler();
45 }
46 }
47
48 public static async void Then(this Task that, IResolvable next) {
49 try {
50 await that;
51 } catch (Exception e) {
52 next.Reject(e);
53 return;
54 }
55 next.Resolve();
56 }
57
58 public static async void Then<T>(this Task<T> that, IResolvable<T> next) {
59 T result;
60 try {
61 result = await that;
62 } catch (Exception e) {
63 next.Reject(e);
64 return;
65 }
66 next.Resolve(result);
67 }
68
69 }
70 } No newline at end of file
@@ -1,17 +1,29
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Threading;
3 using System.Threading;
3 using Xunit;
4 using Xunit;
4
5
5 namespace Implab.Test
6 namespace Implab.Test
6 {
7 {
7 public class UnitTest1
8 public class UnitTest1
8 {
9 {
9 [Fact]
10 [Fact]
10 public void Test1()
11 public void Test1()
11 {
12 {
12 using(var cts = new CancellationTokenSource(1000)) {
13 var listener = new TextWriterTraceListener(Console.Out);
13 PromiseHelper.Sleep(10000, cts.Token).Join();
14 var source = new TraceSource("Custom",SourceLevels.ActivityTracing);
15
16 source.Listeners.Add(listener);
17
18 Trace.Listeners.Add(listener);
19 Trace.WriteLine("Hello!");
20 Trace.CorrelationManager.StartLogicalOperation();
21 Trace.WriteLine("Inner");
22 foreach(var x in Trace.CorrelationManager.LogicalOperationStack)
23 Trace.WriteLine($"-{x}");
24 source.TraceEvent(TraceEventType.Information, 1, "source event");
25 source.TraceData(TraceEventType.Start, 1, DateTime.Now);
26 Trace.CorrelationManager.StopLogicalOperation();
14 }
27 }
15 }
28 }
16 }
29 }
17 }
@@ -1,348 +1,348
1 using Implab;
1 using Implab;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Linq;
4 using System.Linq;
5 using System.Diagnostics;
5 using System.Diagnostics;
6 using System.IO;
6 using System.IO;
7 using System.CodeDom.Compiler;
7 using System.CodeDom.Compiler;
8 using System.CodeDom;
8 using System.CodeDom;
9
9
10 namespace Implab.Automaton {
10 namespace Implab.Automaton {
11 public class DFATable : IDFATableBuilder {
11 public class DFATable : IDFATableBuilder {
12 int m_stateCount;
12 int m_stateCount;
13 int m_symbolCount;
13 int m_symbolCount;
14 int m_initialState;
14 int m_initialState;
15
15
16 readonly HashSet<int> m_finalStates = new HashSet<int>();
16 readonly HashSet<int> m_finalStates = new HashSet<int>();
17 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
17 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
18
18
19
19
20 #region IDFADefinition implementation
20 #region IDFADefinition implementation
21
21
22 public bool IsFinalState(int s) {
22 public bool IsFinalState(int s) {
23 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
23 Safe.ArgumentInRange(s >= 0 && s < m_stateCount, nameof(s));
24
24
25 return m_finalStates.Contains(s);
25 return m_finalStates.Contains(s);
26 }
26 }
27
27
28 public IEnumerable<int> FinalStates {
28 public IEnumerable<int> FinalStates {
29 get {
29 get {
30 return m_finalStates;
30 return m_finalStates;
31 }
31 }
32 }
32 }
33
33
34 public int StateCount {
34 public int StateCount {
35 get { return m_stateCount; }
35 get { return m_stateCount; }
36 }
36 }
37
37
38 public int AlphabetSize {
38 public int AlphabetSize {
39 get { return m_symbolCount; }
39 get { return m_symbolCount; }
40 }
40 }
41
41
42 public int InitialState {
42 public int InitialState {
43 get { return m_initialState; }
43 get { return m_initialState; }
44 }
44 }
45
45
46 #endregion
46 #endregion
47
47
48 public void SetInitialState(int s) {
48 public void SetInitialState(int s) {
49 Safe.ArgumentAssert(s >= 0, "s");
49 Safe.ArgumentInRange(s >= 0, nameof(s));
50 m_stateCount = Math.Max(m_stateCount, s + 1);
50 m_stateCount = Math.Max(m_stateCount, s + 1);
51 m_initialState = s;
51 m_initialState = s;
52 }
52 }
53
53
54 public void MarkFinalState(int state) {
54 public void MarkFinalState(int state) {
55 m_stateCount = Math.Max(m_stateCount, state + 1);
55 m_stateCount = Math.Max(m_stateCount, state + 1);
56 m_finalStates.Add(state);
56 m_finalStates.Add(state);
57 }
57 }
58
58
59 public void Add(AutomatonTransition item) {
59 public void Add(AutomatonTransition item) {
60 Safe.ArgumentAssert(item.s1 >= 0, "item");
60 Safe.ArgumentAssert(item.s1 >= 0, nameof(item));
61 Safe.ArgumentAssert(item.s2 >= 0, "item");
61 Safe.ArgumentAssert(item.s2 >= 0, nameof(item));
62 Safe.ArgumentAssert(item.edge >= 0, "item");
62 Safe.ArgumentAssert(item.edge >= 0, nameof(item));
63
63
64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
66
66
67 m_transitions.Add(item);
67 m_transitions.Add(item);
68 }
68 }
69
69
70 public void Clear() {
70 public void Clear() {
71 m_stateCount = 0;
71 m_stateCount = 0;
72 m_symbolCount = 0;
72 m_symbolCount = 0;
73 m_finalStates.Clear();
73 m_finalStates.Clear();
74 m_transitions.Clear();
74 m_transitions.Clear();
75 }
75 }
76
76
77 public bool Contains(AutomatonTransition item) {
77 public bool Contains(AutomatonTransition item) {
78 return m_transitions.Contains(item);
78 return m_transitions.Contains(item);
79 }
79 }
80
80
81 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
81 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
82 m_transitions.CopyTo(array, arrayIndex);
82 m_transitions.CopyTo(array, arrayIndex);
83 }
83 }
84
84
85 public bool Remove(AutomatonTransition item) {
85 public bool Remove(AutomatonTransition item) {
86 return m_transitions.Remove(item);
86 return m_transitions.Remove(item);
87 }
87 }
88
88
89 public int Count {
89 public int Count {
90 get {
90 get {
91 return m_transitions.Count;
91 return m_transitions.Count;
92 }
92 }
93 }
93 }
94
94
95 public bool IsReadOnly {
95 public bool IsReadOnly {
96 get {
96 get {
97 return false;
97 return false;
98 }
98 }
99 }
99 }
100
100
101 public IEnumerator<AutomatonTransition> GetEnumerator() {
101 public IEnumerator<AutomatonTransition> GetEnumerator() {
102 return m_transitions.GetEnumerator();
102 return m_transitions.GetEnumerator();
103 }
103 }
104
104
105 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
105 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
106 return GetEnumerator();
106 return GetEnumerator();
107 }
107 }
108
108
109 public void AddSymbol(int symbol) {
109 public void AddSymbol(int symbol) {
110 Safe.ArgumentAssert(symbol >= 0, "symbol");
110 Safe.ArgumentAssert(symbol >= 0, "symbol");
111 m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
111 m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
112 }
112 }
113
113
114 public int[,] CreateTransitionTable() {
114 public int[,] CreateTransitionTable() {
115 var table = new int[StateCount,AlphabetSize];
115 var table = new int[StateCount,AlphabetSize];
116
116
117 for (int i = 0; i < StateCount; i++)
117 for (int i = 0; i < StateCount; i++)
118 for (int j = 0; j < AlphabetSize; j++)
118 for (int j = 0; j < AlphabetSize; j++)
119 table[i, j] = AutomatonConst.UnreachableState;
119 table[i, j] = AutomatonConst.UnreachableState;
120
120
121 foreach (var t in this)
121 foreach (var t in this)
122 table[t.s1,t.edge] = (byte)t.s2;
122 table[t.s1,t.edge] = (byte)t.s2;
123
123
124 return table;
124 return table;
125 }
125 }
126
126
127 public bool[] CreateFinalStateTable() {
127 public bool[] CreateFinalStateTable() {
128 var table = new bool[StateCount];
128 var table = new bool[StateCount];
129
129
130 foreach (var s in FinalStates)
130 foreach (var s in FinalStates)
131 table[s] = true;
131 table[s] = true;
132
132
133 return table;
133 return table;
134 }
134 }
135
135
136 /// <summary>Π€ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ мноТСства ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… состояний ΠΏΠ΅Ρ€Π΅Π΄ Π½Π°Ρ‡Π°Π»ΠΎΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ.</summary>
136 /// <summary>Π€ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ мноТСства ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… состояний ΠΏΠ΅Ρ€Π΅Π΄ Π½Π°Ρ‡Π°Π»ΠΎΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ.</summary>
137 /// <remarks>
137 /// <remarks>
138 /// Π’ процСссС построСния минимального Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚Π° трСбуСтся Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ мноТСство состояний,
138 /// Π’ процСссС построСния минимального Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚Π° трСбуСтся Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ мноТСство состояний,
139 /// Π½Π° Π΄Π²Π° подмноТСства - ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Π΅ состояния ΠΈ всС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅, послС Ρ‡Π΅Π³ΠΎ эти подмноТСства
139 /// Π½Π° Π΄Π²Π° подмноТСства - ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Π΅ состояния ΠΈ всС ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅, послС Ρ‡Π΅Π³ΠΎ эти подмноТСства
140 /// Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π΅Π·Π΄Π΅Π»Π΅Π½Ρ‹ Π½Π° Π±ΠΎΠ»Π΅Π΅ ΠΌΠ΅Π»ΠΊΠΈΠ΅. Иногда трСбуСтся Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ различия ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… сосотяний,
140 /// Π±ΡƒΠ΄ΡƒΡ‚ Ρ€Π΅Π·Π΄Π΅Π»Π΅Π½Ρ‹ Π½Π° Π±ΠΎΠ»Π΅Π΅ ΠΌΠ΅Π»ΠΊΠΈΠ΅. Иногда трСбуСтся Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ различия ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… сосотяний,
141 /// для этого Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ†ΡŽ Ρ„ΡƒΠΊΠ½Ρ†ΠΈΡŽ, для получСния мноТСств ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… состояний.
141 /// для этого Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ†ΡŽ Ρ„ΡƒΠΊΠ½Ρ†ΠΈΡŽ, для получСния мноТСств ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… состояний.
142 /// </remarks>
142 /// </remarks>
143 /// <returns>The final states.</returns>
143 /// <returns>The final states.</returns>
144 protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
144 protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
145 return new [] { new HashSet<int>(states) };
145 return new [] { new HashSet<int>(states) };
146 }
146 }
147
147
148 protected void Optimize(
148 protected void Optimize(
149 IDFATableBuilder optimalDFA,
149 IDFATableBuilder optimalDFA,
150 IDictionary<int,int> alphabetMap,
150 IDictionary<int,int> alphabetMap,
151 IDictionary<int,int> stateMap
151 IDictionary<int,int> stateMap
152 ) {
152 ) {
153 Safe.ArgumentNotNull(optimalDFA, "dfa");
153 Safe.ArgumentNotNull(optimalDFA, "dfa");
154 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
154 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
155 Safe.ArgumentNotNull(stateMap, "stateMap");
155 Safe.ArgumentNotNull(stateMap, "stateMap");
156
156
157
157
158 var setComparer = new CustomEqualityComparer<HashSet<int>>(
158 var setComparer = new CustomEqualityComparer<HashSet<int>>(
159 (x, y) => x.SetEquals(y),
159 (x, y) => x.SetEquals(y),
160 s => s.Sum(x => x.GetHashCode())
160 s => s.Sum(x => x.GetHashCode())
161 );
161 );
162
162
163 var optimalStates = new HashSet<HashSet<int>>(setComparer);
163 var optimalStates = new HashSet<HashSet<int>>(setComparer);
164 var queue = new HashSet<HashSet<int>>(setComparer);
164 var queue = new HashSet<HashSet<int>>(setComparer);
165
165
166 optimalStates.Add(new HashSet<int>(FinalStates));
166 optimalStates.Add(new HashSet<int>(FinalStates));
167
167
168 var state = new HashSet<int>(
168 var state = new HashSet<int>(
169 Enumerable
169 Enumerable
170 .Range(0, m_stateCount)
170 .Range(0, m_stateCount)
171 .Where(i => !m_finalStates.Contains(i))
171 .Where(i => !m_finalStates.Contains(i))
172 );
172 );
173
173
174 optimalStates.Add(state);
174 optimalStates.Add(state);
175 queue.Add(state);
175 queue.Add(state);
176
176
177 var rmap = m_transitions
177 var rmap = m_transitions
178 .GroupBy(t => t.s2)
178 .GroupBy(t => t.s2)
179 .ToDictionary(
179 .ToDictionary(
180 g => g.Key, // s2
180 g => g.Key, // s2
181 g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key)
181 g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key)
182 );
182 );
183
183
184 while (queue.Count > 0) {
184 while (queue.Count > 0) {
185 var stateA = queue.First();
185 var stateA = queue.First();
186 queue.Remove(stateA);
186 queue.Remove(stateA);
187
187
188 for (int c = 0; c < m_symbolCount; c++) {
188 for (int c = 0; c < m_symbolCount; c++) {
189 var stateX = new HashSet<int>();
189 var stateX = new HashSet<int>();
190 foreach(var a in stateA.Where(rmap.ContainsKey))
190 foreach(var a in stateA.Where(rmap.ContainsKey))
191 stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
191 stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
192
192
193 var tmp = optimalStates.ToArray();
193 var tmp = optimalStates.ToArray();
194 foreach (var stateY in tmp) {
194 foreach (var stateY in tmp) {
195 var stateR1 = new HashSet<int>(stateY);
195 var stateR1 = new HashSet<int>(stateY);
196 var stateR2 = new HashSet<int>(stateY);
196 var stateR2 = new HashSet<int>(stateY);
197
197
198 stateR1.IntersectWith(stateX);
198 stateR1.IntersectWith(stateX);
199 stateR2.ExceptWith(stateX);
199 stateR2.ExceptWith(stateX);
200
200
201 if (stateR1.Count > 0 && stateR2.Count > 0) {
201 if (stateR1.Count > 0 && stateR2.Count > 0) {
202
202
203
203
204 optimalStates.Remove(stateY);
204 optimalStates.Remove(stateY);
205 optimalStates.Add(stateR1);
205 optimalStates.Add(stateR1);
206 optimalStates.Add(stateR2);
206 optimalStates.Add(stateR2);
207
207
208 if (queue.Contains(stateY)) {
208 if (queue.Contains(stateY)) {
209 queue.Remove(stateY);
209 queue.Remove(stateY);
210 queue.Add(stateR1);
210 queue.Add(stateR1);
211 queue.Add(stateR2);
211 queue.Add(stateR2);
212 } else {
212 } else {
213 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
213 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
214 }
214 }
215 }
215 }
216 }
216 }
217 }
217 }
218 }
218 }
219
219
220 // Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ€Π°Π·Π±ΠΈΠ²Π°Π΅ΠΌ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Π΅ состояния
220 // Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ€Π°Π·Π±ΠΈΠ²Π°Π΅ΠΌ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Π΅ состояния
221 foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) {
221 foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) {
222 optimalStates.Remove(final);
222 optimalStates.Remove(final);
223 foreach (var split in SplitFinalStates(final))
223 foreach (var split in SplitFinalStates(final))
224 optimalStates.Add(split);
224 optimalStates.Add(split);
225 }
225 }
226
226
227
227
228 // ΠΊΠ°Ρ€Ρ‚Π° получСния ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ состояния ΠΏΠΎ ΡΠΎΠΎΡ‚Π²Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΌΡƒ Π΅ΠΌΡƒ простому ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ
228 // ΠΊΠ°Ρ€Ρ‚Π° получСния ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ состояния ΠΏΠΎ ΡΠΎΠΎΡ‚Π²Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΌΡƒ Π΅ΠΌΡƒ простому ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ
229 var nextState = 0;
229 var nextState = 0;
230 foreach (var item in optimalStates) {
230 foreach (var item in optimalStates) {
231 var id = nextState++;
231 var id = nextState++;
232 foreach (var s in item)
232 foreach (var s in item)
233 stateMap[s] = id;
233 stateMap[s] = id;
234 }
234 }
235
235
236 // ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Π°Π»Ρ„Π°Π²ΠΈΡ‚
236 // ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Π°Π»Ρ„Π°Π²ΠΈΡ‚
237 // Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ символы Π½Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹, Ссли Move(s,a1) == Move(s,a2), для любого s
237 // Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ символы Π½Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹, Ссли Move(s,a1) == Move(s,a2), для любого s
238 // для этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ кластСризации, сначала
238 // для этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ кластСризации, сначала
239 // считаСм, Ρ‡Ρ‚ΠΎ всС символы Π½Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹
239 // считаСм, Ρ‡Ρ‚ΠΎ всС символы Π½Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹
240
240
241 var minClasses = new HashSet<HashSet<int>>(setComparer);
241 var minClasses = new HashSet<HashSet<int>>(setComparer);
242 var alphaQueue = new Queue<HashSet<int>>();
242 var alphaQueue = new Queue<HashSet<int>>();
243 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
243 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
244
244
245 // для всСх состояний, Π±ΡƒΠ΄Π΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ класс Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΠΎΡΡ‚ΡŒ,
245 // для всСх состояний, Π±ΡƒΠ΄Π΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ класс Π½Π° Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΠΎΡΡ‚ΡŒ,
246 // Ρ‚.Π΅. символы Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹, Ссли ΠΎΠ½ΠΈ приводят ΠΊ Ρ€Π°Π·Π½Ρ‹ΠΌ состояниям
246 // Ρ‚.Π΅. символы Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹, Ссли ΠΎΠ½ΠΈ приводят ΠΊ Ρ€Π°Π·Π½Ρ‹ΠΌ состояниям
247 for (int s = 0 ; s < optimalStates.Count; s++) {
247 for (int s = 0 ; s < optimalStates.Count; s++) {
248 var newQueue = new Queue<HashSet<int>>();
248 var newQueue = new Queue<HashSet<int>>();
249
249
250 foreach (var A in alphaQueue) {
250 foreach (var A in alphaQueue) {
251 // классы ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ символа Π΄Π΅Π»ΠΈΡ‚ΡŒ бСсполСзно, ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΈΠΌ ΠΈΡ… сразу Π²
251 // классы ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ символа Π΄Π΅Π»ΠΈΡ‚ΡŒ бСсполСзно, ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΈΠΌ ΠΈΡ… сразу Π²
252 // Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ Π°Π»Ρ„Π°Π²ΠΈΡ‚
252 // Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ Π°Π»Ρ„Π°Π²ΠΈΡ‚
253 if (A.Count == 1) {
253 if (A.Count == 1) {
254 minClasses.Add(A);
254 minClasses.Add(A);
255 continue;
255 continue;
256 }
256 }
257
257
258 // Ρ€Π°Π·Π»ΠΈΡ‡Π°Π΅ΠΌ классы символов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ пСрСводят Π² Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ состояния
258 // Ρ€Π°Π·Π»ΠΈΡ‡Π°Π΅ΠΌ классы символов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ пСрСводят Π² Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ состояния
259 // optimalState -> alphaClass
259 // optimalState -> alphaClass
260 var classes = new Dictionary<int, HashSet<int>>();
260 var classes = new Dictionary<int, HashSet<int>>();
261
261
262 foreach (var term in A) {
262 foreach (var term in A) {
263 // ΠΈΡ‰Π΅ΠΌ всС ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Ρ‹ класса ΠΏΠΎ символу term
263 // ΠΈΡ‰Π΅ΠΌ всС ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Ρ‹ класса ΠΏΠΎ символу term
264 var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
264 var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
265
265
266 HashSet<int> a2;
266 HashSet<int> a2;
267 if (!classes.TryGetValue(s2, out a2)) {
267 if (!classes.TryGetValue(s2, out a2)) {
268 a2 = new HashSet<int>();
268 a2 = new HashSet<int>();
269 newQueue.Enqueue(a2);
269 newQueue.Enqueue(a2);
270 classes[s2] = a2;
270 classes[s2] = a2;
271 }
271 }
272 a2.Add(term);
272 a2.Add(term);
273 }
273 }
274 }
274 }
275
275
276 if (newQueue.Count == 0)
276 if (newQueue.Count == 0)
277 break;
277 break;
278 alphaQueue = newQueue;
278 alphaQueue = newQueue;
279 }
279 }
280
280
281 // послС окончания Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ останутся ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹Π΅ классы
281 // послС окончания Ρ€Π°Π±ΠΎΡ‚Ρ‹ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠ° Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ останутся ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹Π΅ классы
282 // Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… символов
282 // Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… символов
283 foreach (var A in alphaQueue)
283 foreach (var A in alphaQueue)
284 minClasses.Add(A);
284 minClasses.Add(A);
285
285
286 // построСниС отобраТСния Π°Π»Ρ„Π°Π²ΠΈΡ‚ΠΎΠ² Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… символов.
286 // построСниС отобраТСния Π°Π»Ρ„Π°Π²ΠΈΡ‚ΠΎΠ² Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… символов.
287 // ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ символ DFAConst.UNCLASSIFIED_INPUT ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ
287 // ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ символ DFAConst.UNCLASSIFIED_INPUT ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ
288 // ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎΠ³Π΄Π° сохраним ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ класс,
288 // ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎΠ³Π΄Π° сохраним ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ класс,
289 // содСрТащий этот символ Π½Π° Ρ‚ΠΎΠΌΠΆΠ΅ мСстС.
289 // содСрТащий этот символ Π½Π° Ρ‚ΠΎΠΌΠΆΠ΅ мСстС.
290
290
291 var nextCls = 0;
291 var nextCls = 0;
292 foreach (var item in minClasses) {
292 foreach (var item in minClasses) {
293 if (nextCls == AutomatonConst.UnclassifiedInput)
293 if (nextCls == AutomatonConst.UnclassifiedInput)
294 nextCls++;
294 nextCls++;
295
295
296 // сохраняСм DFAConst.UNCLASSIFIED_INPUT
296 // сохраняСм DFAConst.UNCLASSIFIED_INPUT
297 var cls = item.Contains(AutomatonConst.UnclassifiedInput) ? AutomatonConst.UnclassifiedInput : nextCls++;
297 var cls = item.Contains(AutomatonConst.UnclassifiedInput) ? AutomatonConst.UnclassifiedInput : nextCls++;
298 optimalDFA.AddSymbol(cls);
298 optimalDFA.AddSymbol(cls);
299
299
300 foreach (var a in item)
300 foreach (var a in item)
301 alphabetMap[a] = cls;
301 alphabetMap[a] = cls;
302 }
302 }
303
303
304 // построСниС Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚Π°
304 // построСниС Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚Π°
305 optimalDFA.SetInitialState(stateMap[m_initialState]);
305 optimalDFA.SetInitialState(stateMap[m_initialState]);
306
306
307 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
307 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
308 optimalDFA.MarkFinalState(sf);
308 optimalDFA.MarkFinalState(sf);
309
309
310 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
310 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
311 optimalDFA.Add(t);
311 optimalDFA.Add(t);
312 }
312 }
313
313
314 /*protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
314 /*protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
317
317
318 var data = new List<string>();
318 var data = new List<string>();
319
319
320 data.Add("digraph dfa {");
320 data.Add("digraph dfa {");
321
321
322 foreach (var final in m_finalStates)
322 foreach (var final in m_finalStates)
323 data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
323 data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
324
324
325 foreach (var t in m_transitions)
325 foreach (var t in m_transitions)
326 data.Add(String.Format(
326 data.Add(String.Format(
327 "{0} -> {2} [label={1}];",
327 "{0} -> {2} [label={1}];",
328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UnclassifiedInput ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UnclassifiedInput ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
330 String.Join("", stateAlphabet.GetSymbols(t.s2))
330 String.Join("", stateAlphabet.GetSymbols(t.s2))
331 ));
331 ));
332 data.Add("}");
332 data.Add("}");
333 return String.Join("\n", data);
333 return String.Join("\n", data);
334 }
334 }
335
335
336 static string ToLiteral(string input)
336 static string ToLiteral(string input)
337 {
337 {
338 using (var writer = new StringWriter())
338 using (var writer = new StringWriter())
339 {
339 {
340 using (var provider = CodeDomProvider.CreateProvider("CSharp"))
340 using (var provider = CodeDomProvider.CreateProvider("CSharp"))
341 {
341 {
342 provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
342 provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
343 return writer.ToString();
343 return writer.ToString();
344 }
344 }
345 }
345 }
346 }*/
346 }*/
347 }
347 }
348 }
348 }
@@ -1,24 +1,26
1 namespace Implab.Components {
1 namespace Implab.Components {
2
2
3 public enum ExecutionState {
3 public enum ExecutionState {
4 Undefined = 0,
4 Undefined = 0,
5
5
6 Created,
6 Created,
7
7
8 Initializing,
8 Initializing,
9
9
10 Ready,
10 Ready,
11
11
12 Starting,
12 Starting,
13
13
14 Running,
14 Running,
15
15
16 Stopping,
16 Stopping,
17
17
18 Stopped,
19
18 Failed,
20 Failed,
19
21
20 Disposed,
22 Disposed,
21
23
22 Last = Disposed
24 Last = Disposed
23 }
25 }
24 } No newline at end of file
26 }
@@ -1,21 +1,28
1 using System;
1 using System;
2
2
3 namespace Implab.Components {
3 namespace Implab.Components {
4 /// <summary>
4 /// <summary>
5 /// Initializable components are created and initialized in two steps, first we have create the component,
5 /// Initializable components are created and initialized in two steps, first we have create the component,
6 /// then we have to complete it's creation by calling an <see cref="Initialize()"/> method. All parameters needed
6 /// then we have to complete it's creation by calling an <see cref="Initialize()"/> method. All parameters needed
7 /// to complete the initialization must be passed before the calling <see cref="Initialize()"/>
7 /// to complete the initialization must be passed before the calling <see cref="Initialize()"/>
8 /// </summary>
8 /// </summary>
9 public interface IInitializable {
9 public interface IInitializable {
10 /// <summary>
10 /// <summary>
11 /// Completes initialization.
11 /// Completes initialization.
12 /// </summary>
12 /// </summary>
13 /// <remarks>
13 /// <remarks>
14 /// <para>
14 /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but
15 /// Normally virtual methods shouldn't be called from the constructor, due to the incomplete object state, but
15 /// they can be called from this method. This method is also usefull when we constructing a complex grpah
16 /// they can be called from this method. This method is also usefull when we constructing a complex grpah
16 /// of components where cyclic references may take place.
17 /// of components where cyclic references may take place.
18 /// </para>
19 /// <para>
20 /// In asyncronous patterns <see cref="Initialize()"/> can be called
21 /// to start initialization and the <see cref="IRunnable.Completion"/>
22 /// property can be used to track operation completion.
23 /// </para>
17 /// </remarks>
24 /// </remarks>
18 void Initialize();
25 void Initialize();
19 }
26 }
20 }
27 }
21
28
@@ -1,29 +1,59
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4
4
5 namespace Implab.Components {
5 namespace Implab.Components {
6 /// <summary>
6 /// <summary>
7 /// Interface for the component which performs a long running task.
7 /// Interface for the component which performs a long running task.
8 /// </summary>
8 /// </summary>
9 public interface IRunnable : IDisposable {
9 /// <remarks>
10 /// The access to the runnable component should be sequential, the
11 /// componet should support asynchronous completion of the initiated
12 /// operation but operations itself must be initiated sequentially.
13 /// </remarks>
14 public interface IRunnable {
10 /// <summary>
15 /// <summary>
11 /// Starts this instance
16 /// Starts this instance
12 /// </summary>
17 /// </summary>
18 /// <remarks>
19 /// This operation is cancellable and it's expected to move to
20 /// the failed state or just ignore the cancellation request,
21 /// </remarks>
13 void Start(CancellationToken ct);
22 void Start(CancellationToken ct);
14
23
15 /// <summary>
24 /// <summary>
16 /// Stops this instance and releases all resources, after the instance is stopped it is moved to Disposed state and can't be reused.
25 /// Stops this instance and releases all resources, after the
26 /// instance is stopped it is moved to Disposed state and
27 /// can't be reused.
17 /// </summary>
28 /// </summary>
29 /// <remarks>
30 /// If the componet was in the starting state the pending operation
31 /// will be requested to cancel. The stop operatin will be
32 /// performed only if the component in the running state.
33 /// </remarks>
18 void Stop(CancellationToken ct);
34 void Stop(CancellationToken ct);
19
35
20 Task<ExecutionState> Completion { get; }
36 /// <summary>
37 /// The result of the last started operation. This property reflects
38 /// only the result of the last started operation and therefore should
39 /// change only if a new operation is initiated.
40 /// </summary>
41 Task Completion { get; }
21
42
43 /// <summary>
44 /// Current state of the componenet
45 /// </summary>
22 ExecutionState State { get; }
46 ExecutionState State { get; }
23
47
48 /// <summary>
49 /// Event to monitor the state of the component.
50 /// </summary>
24 event EventHandler<StateChangeEventArgs> StateChanged;
51 event EventHandler<StateChangeEventArgs> StateChanged;
25
52
53 /// <summary>
54 /// The last error
55 /// </summary>
26 Exception LastError { get; }
56 Exception LastError { get; }
27 }
57 }
28 }
58 }
29
59
@@ -1,75 +1,75
1 using Implab.Parallels;
1 using Implab.Parallels;
2 using System;
2 using System;
3 using System.Threading;
3 using System.Threading;
4
4
5 namespace Implab.Components {
5 namespace Implab.Components {
6 /// <summary>
6 /// <summary>
7 /// The base class for creating object pools.
7 /// The base class for creating object pools.
8 /// </summary>
8 /// </summary>
9 /// <remarks>
9 /// <remarks>
10 /// <para>The objects pool is offers frequently requested objects to be reused, this gives
10 /// <para>The objects pool is offers frequently requested objects to be reused, this gives
11 /// a gool speed improvement for the 'heavy' objects. To avoid memory overhead the pool uses
11 /// a gool speed improvement for the 'heavy' objects. To avoid memory overhead the pool uses
12 /// weak references allowing CG to do it's work. If there are no free objects in the pool
12 /// weak references allowing CG to do it's work. If there are no free objects in the pool
13 /// they are created on demand. </para>
13 /// they are created on demand. </para>
14 /// <para>
14 /// <para>
15 /// Implementors need to defined a <see cref="CreateInstance()"/> method
15 /// Implementors need to defined a <see cref="CreateInstance()"/> method
16 /// </para>
16 /// </para>
17 /// <para>The instances of this class are thred-safe.</para>
17 /// <para>The instances of this class are thred-safe.</para>
18 /// </remarks>
18 /// </remarks>
19 public abstract class ObjectPool<T> where T : class {
19 public abstract class ObjectPool<T> where T : class {
20 readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<WeakReference>();
20 readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<WeakReference>();
21 readonly int m_size;
21 readonly int m_size;
22 int m_count = 0;
22 int m_count = 0;
23
23
24 protected ObjectPool() : this(Environment.ProcessorCount+1) {
24 protected ObjectPool() : this(Environment.ProcessorCount+1) {
25
25
26 }
26 }
27
27
28 protected ObjectPool(int size) {
28 protected ObjectPool(int size) {
29 Safe.ArgumentInRange(size,1,size,"size");
29 Safe.ArgumentInRange(size > 0, nameof(size));
30
30
31 m_size = size;
31 m_size = size;
32 }
32 }
33
33
34 /// <summary>
34 /// <summary>
35 /// Creates the instance if there are no free ones in the pool.
35 /// Creates the instance if there are no free ones in the pool.
36 /// </summary>
36 /// </summary>
37 /// <returns>The new instance.</returns>
37 /// <returns>The new instance.</returns>
38 protected abstract T CreateInstance();
38 protected abstract T CreateInstance();
39
39
40 /// <summary>
40 /// <summary>
41 /// Cleanups the instance.
41 /// Cleanups the instance.
42 /// </summary>
42 /// </summary>
43 /// <param name="instance">The instance to cleanup and prepare it for the next use.</param>
43 /// <param name="instance">The instance to cleanup and prepare it for the next use.</param>
44 protected virtual void CleanupInstance(T instance) {
44 protected virtual void CleanupInstance(T instance) {
45 }
45 }
46
46
47 /// <summary>
47 /// <summary>
48 /// Allocate free instance from the pool or reates a new one.
48 /// Allocate free instance from the pool or reates a new one.
49 /// </summary>
49 /// </summary>
50 public T Allocate() {
50 public T Allocate() {
51 WeakReference reference;
51 WeakReference reference;
52 while (m_queue.TryDequeue(out reference)) {
52 while (m_queue.TryDequeue(out reference)) {
53 Interlocked.Decrement(ref m_count);
53 Interlocked.Decrement(ref m_count);
54 object instance = reference.Target;
54 object instance = reference.Target;
55 if (instance == null)
55 if (instance == null)
56 continue;
56 continue;
57 return (T)instance;
57 return (T)instance;
58 }
58 }
59 return CreateInstance();
59 return CreateInstance();
60 }
60 }
61
61
62 /// <summary>
62 /// <summary>
63 /// Release the specified instance and returns it to the pool of free instances.
63 /// Release the specified instance and returns it to the pool of free instances.
64 /// </summary>
64 /// </summary>
65 /// <param name="instance">The instance to return to the pool.</param>
65 /// <param name="instance">The instance to return to the pool.</param>
66 /// <remarks>Before the instance is returned to the pool the <see cref="CleanupInstance(T)"/> is called.</remarks>
66 /// <remarks>Before the instance is returned to the pool the <see cref="CleanupInstance(T)"/> is called.</remarks>
67 public void Release(T instance) {
67 public void Release(T instance) {
68 if (m_count < m_size && instance != null) {
68 if (m_count < m_size && instance != null) {
69 Interlocked.Increment(ref m_count);
69 Interlocked.Increment(ref m_count);
70 CleanupInstance(instance);
70 CleanupInstance(instance);
71 m_queue.Enqueue(new WeakReference(instance));
71 m_queue.Enqueue(new WeakReference(instance));
72 }
72 }
73 }
73 }
74 }
74 }
75 }
75 }
@@ -1,57 +1,273
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Threading;
3 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Threading.Tasks;
4
5
5 namespace Implab.Components
6 namespace Implab.Components {
6 {
7 /// <summary>
7 public class RunnableComponent : IRunnable {
8 /// Base class for implementing components which support start and stop operations,
9 /// such components may represent running services.
10 /// </summary>
11 /// <remarks>
12 /// This class provides a basic lifecycle from the creation to the
13 /// termination of the component.
14 /// </remarks>
15 public class RunnableComponent : IRunnable, IInitializable, IDisposable {
16
17 /// <summary>
18 /// This class bound <see cref="CancellationTokenSource"/> lifetime to the task,
19 /// when the task completes the associated token source will be disposed.
20 /// </summary>
21 class AsyncOperationDescriptor {
22
23 public static AsyncOperationDescriptor None { get; } = new AsyncOperationDescriptor();
24
25 readonly CancellationTokenSource m_cts;
26
27 bool m_done;
28
29 public CancellationToken Token {
30 get { return m_cts == null ? CancellationToken.None : m_cts.Token; }
31 }
32
33 public Task Task { get; private set; }
34
35 private AsyncOperationDescriptor(Task task, CancellationTokenSource cts) {
36 m_cts = cts;
37 Task = Chain(task);
38 }
39
40 private AsyncOperationDescriptor() {
41 Task = Task.CompletedTask;
42 }
8
43
44 public void Cancel() {
45 if (m_cts != null) {
46 lock (m_cts) {
47 if (!m_done)
48 m_cts.Cancel();
49 }
50 }
51 }
52
53 void Done() {
54 if (m_cts != null) {
55 lock (m_cts) {
56 m_done = true;
57 m_cts.Dispose();
58 }
59 } else {
60 m_done = true;
61 }
62 }
63
64 async Task Chain(Task other) {
65 try {
66 await other;
67 } finally {
68 Done();
69 }
70 }
71
72 public static AsyncOperationDescriptor Create(Func<CancellationToken, Task> factory, CancellationToken ct) {
73 var cts = ct.CanBeCanceled ?
74 CancellationTokenSource.CreateLinkedTokenSource(ct) :
75 new CancellationTokenSource();
76
77 return new AsyncOperationDescriptor(factory(cts.Token), cts);
78 }
79
80 }
81
82 // this lock is used to synchronize state flow of the component during
83 // completions or the operations.
9 readonly object m_lock = new object();
84 readonly object m_lock = new object();
10
85
11 CancellationTokenSource m_cts;
86 // current operation cookie, used to check wheather a call to
87 // MoveSuccess/MoveFailed method belongs to the current
88 // operation, if cookies didn't match ignore completion result.
89 object m_cookie;
12
90
13 public Task<ExecutionState> Completion {
91 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
14 get;
92
15 private set;
93 ExecutionState m_state;
94
95
96 protected RunnableComponent(bool initialized) {
97 State = initialized ? ExecutionState.Ready : ExecutionState.Created;
16 }
98 }
17
99
18 public ExecutionState State => throw new NotImplementedException();
100 public Task Completion {
101 get { return m_current.Task; }
102 }
19
103
20 public Exception LastError => throw new NotImplementedException();
104 public ExecutionState State {
105 get { return m_state; }
106 private set {
107 if (m_state != value) {
108 m_state = value;
109 StateChanged.DispatchEvent(this, new StateChangeEventArgs {
110 State = value,
111 LastError = LastError
112 });
113 }
114 }
115 }
116
117 public Exception LastError { get; private set; }
21
118
22 public event EventHandler<StateChangeEventArgs> StateChanged;
119 public event EventHandler<StateChangeEventArgs> StateChanged;
23
120
121 /// <summary>
122 /// Releases all resources used by the current component regardless of its
123 /// execution state.
124 /// </summary>
125 /// <remarks>
126 /// Calling to this method may result unexpedted results if the component
127 /// isn't in the stopped state. Call this method after the component is
128 /// stopped if needed or if the component is in the failed state.
129 /// </remarks>
24 public void Dispose() {
130 public void Dispose() {
25 lock(m_lock) {
131 bool dispose = false;
132 if (dispose) {
26 Dispose(true);
133 Dispose(true);
27 GC.SuppressFinalize(this);
134 GC.SuppressFinalize(this);
28 }
135 }
29 }
136 }
30
137
138 ~RunnableComponent() {
139 Dispose(false);
140 }
141
142 /// <summary>
143 /// Releases all resources used by the current component regardless of its
144 /// execution state.
145 /// </summary>
146 /// <param name="disposing">Indicates that the component is disposed
147 /// during a normal disposing or during GC.</param>
31 protected virtual void Dispose(bool disposing) {
148 protected virtual void Dispose(bool disposing) {
32 if (disposing) {
149 }
33 Safe.Dispose(m_cts);
150
151 public void Initialize() {
152 var cookie = new object();
153 if (MoveInitialize(cookie))
154 ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie);
34 }
155 }
156
157 /// <summary>
158 /// This method is used for initialization during a component creation.
159 /// </summary>
160 /// <param name="ct">A cancellation token for this operation</param>
161 /// <remarks>
162 /// This method should be used for short and mostly syncronous operations,
163 /// other operations which require time to run shoud be placed in
164 /// <see cref="StartInternal(CancellationToken)"/> method.
165 /// </remarks>
166 protected virtual Task InitializeInternalAsync(CancellationToken ct) {
167 return Task.CompletedTask;
35 }
168 }
36
169
37 public void Start(CancellationToken ct) {
170 public void Start(CancellationToken ct) {
171 var cookie = new object();
172 if (MoveStart(cookie))
173 ScheduleTask(StartInternal, ct, cookie);
174 }
175
176 protected virtual Task StartInternal(CancellationToken ct) {
177 return Task.CompletedTask;
178 }
179
180 public void Stop(CancellationToken ct) {
181 var cookie = new object();
182 if (MoveStop(cookie))
183 ScheduleTask(StopAsync, ct, cookie);
184 }
185
186 async Task StopAsync(CancellationToken ct) {
187 m_current.Cancel();
188 await Completion;
189
190 ct.ThrowIfCancellationRequested();
191
192 await StopInternalAsync(ct);
193 }
194
195 protected virtual Task StopInternalAsync(CancellationToken ct) {
196 return Task.CompletedTask;
197 }
198
199
200 #region state management
201
202 bool MoveInitialize(object cookie) {
38 lock(m_lock) {
203 lock (m_lock) {
39 switch (State)
204 if (State != ExecutionState.Created)
40 {
205 return false;
206 State = ExecutionState.Initializing;
207 m_cookie = cookie;
208 return true;
209 }
210 }
211
212 bool MoveStart(object cookie) {
213 lock (m_lock) {
214 if (State != ExecutionState.Ready)
215 return false;
216 State = ExecutionState.Starting;
217 m_cookie = cookie;
218 return true;
219 }
220 }
41
221
42 default:
222 bool MoveStop(object cookie) {
43 throw new InvalidOperationException();
223 lock (m_lock) {
224 if (State != ExecutionState.Starting && State != ExecutionState.Running)
225 return false;
226 State = ExecutionState.Stopping;
227 m_cookie = cookie;
228 return true;
229 }
230 }
231
232 void MoveSuccess(object cookie) {
233 lock (m_lock) {
234 if (m_cookie != cookie)
235 return;
236 switch (State) {
237 case ExecutionState.Initializing:
238 State = ExecutionState.Ready;
239 break;
240 case ExecutionState.Starting:
241 State = ExecutionState.Running;
242 break;
243 case ExecutionState.Stopping:
244 State = ExecutionState.Stopped;
245 break;
44 }
246 }
45 }
247 }
46 }
248 }
47
249
48 public void Stop(CancellationToken ct) {
250 void MoveFailed(Exception err, object cookie) {
49 throw new NotImplementedException();
251 lock (m_lock) {
252 if (m_cookie != cookie)
253 return;
254 LastError = err;
255 State = ExecutionState.Failed;
256 }
50 }
257 }
51
258
52 protected virtual Task StartImpl(CancellationToken ct) {
259
53
260
54 return Task.CompletedTask;
261 protected async void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) {
262 try {
263 m_current = AsyncOperationDescriptor.Create(next, ct);
264 await m_current.Task;
265 MoveSuccess(cookie);
266 } catch (Exception e) {
267 MoveFailed(e, cookie);
55 }
268 }
56 }
269 }
270
271 #endregion
272 }
57 } No newline at end of file
273 }
@@ -1,53 +1,64
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.Threading.Tasks;
3
4
4 namespace Implab {
5 namespace Implab {
5 /// <summary>
6 /// <summary>
6 /// This class is responsible for the promise resolution, dispatching and chaining
7 /// This class is responsible for the promise resolution, dispatching and chaining
7 /// </summary>
8 /// </summary>
8 public class Deferred : IResolvable {
9 public class Deferred : IResolvable {
9
10
10 readonly Promise m_promise;
11 readonly Promise m_promise;
11 internal Deferred() {
12 internal Deferred() {
12 m_promise = new Promise();
13 m_promise = new Promise();
13 }
14 }
14
15
15 internal Deferred(Promise promise, IDispatcher dispatcher) {
16 internal Deferred(Promise promise, IDispatcher dispatcher) {
16 Debug.Assert(promise != null);
17 Debug.Assert(promise != null);
17 m_promise = promise;
18 m_promise = promise;
18 }
19 }
19
20
20 public IPromise Promise {
21 public IPromise Promise {
21 get { return m_promise; }
22 get { return m_promise; }
22 }
23 }
23
24
24 public void Cancel() {
25 public void Cancel() {
25 Reject(new OperationCanceledException());
26 Reject(new OperationCanceledException());
26 }
27 }
27
28
28 public virtual void Reject(Exception error) {
29 public virtual void Reject(Exception error) {
29 if (error is PromiseTransientException)
30 if (error is PromiseTransientException)
30 error = ((PromiseTransientException)error).InnerException;
31 error = ((PromiseTransientException)error).InnerException;
31
32
32 m_promise.RejectPromise(error);
33 m_promise.RejectPromise(error);
33 }
34 }
34
35
35 public virtual void Resolve() {
36 public virtual void Resolve() {
36 m_promise.ResolvePromise();
37 m_promise.ResolvePromise();
37 }
38 }
38
39
39 public virtual void Resolve(IPromise thenable) {
40 public virtual void Resolve(IPromise thenable) {
40 if (thenable == null)
41 if (thenable == null)
41 Reject(new Exception("The promise or task are expected"));
42 Reject(new Exception("The promise or task are expected"));
42 if (thenable == m_promise)
43 if (thenable == m_promise)
43 Reject(new Exception("The promise cannot be resolved with oneself"));
44 Reject(new Exception("The promise cannot be resolved with oneself"));
44
45
45 try {
46 try {
46 thenable.Then(this);
47 thenable.Then(this);
47 } catch (Exception err) {
48 } catch (Exception err) {
48 Reject(err);
49 Reject(err);
49 }
50 }
50 }
51 }
51
52
53 public virtual void Resolve(Task thenable) {
54 if (thenable == null)
55 Reject(new Exception("The promise or task are expected"));
56 try {
57 thenable.Then(this);
58 } catch(Exception err) {
59 Reject(err);
60 }
61 }
62
52 }
63 }
53 } No newline at end of file
64 }
@@ -1,49 +1,61
1 using System;
1 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.Threading.Tasks;
3
4
4 namespace Implab {
5 namespace Implab {
5 public class Deferred<T> : IResolvable<T> {
6 public class Deferred<T> : IResolvable<T> {
6 readonly Promise<T> m_promise;
7 readonly Promise<T> m_promise;
7
8
8 internal Deferred() {
9 internal Deferred() {
9 m_promise = new Promise<T>();
10 m_promise = new Promise<T>();
10 }
11 }
11
12
12 protected Deferred(Promise<T> promise) {
13 protected Deferred(Promise<T> promise) {
13 Debug.Assert(promise != null);
14 Debug.Assert(promise != null);
14 m_promise = promise;
15 m_promise = promise;
15 }
16 }
16
17
17 public IPromise<T> Promise {
18 public IPromise<T> Promise {
18 get { return m_promise; }
19 get { return m_promise; }
19 }
20 }
20
21
21 public void Cancel() {
22 public void Cancel() {
22 Reject(new OperationCanceledException());
23 Reject(new OperationCanceledException());
23 }
24 }
24
25
25 public virtual void Reject(Exception error) {
26 public virtual void Reject(Exception error) {
26 if (error is PromiseTransientException)
27 if (error is PromiseTransientException)
27 error = ((PromiseTransientException)error).InnerException;
28 error = ((PromiseTransientException)error).InnerException;
28
29
29 m_promise.RejectPromise(error);
30 m_promise.RejectPromise(error);
30 }
31 }
31
32
32 public virtual void Resolve(T value) {
33 public virtual void Resolve(T value) {
33 m_promise.ResolvePromise(value);
34 m_promise.ResolvePromise(value);
34 }
35 }
35
36
36 public virtual void Resolve(IPromise<T> thenable) {
37 public virtual void Resolve(IPromise<T> thenable) {
37 if (thenable == null)
38 if (thenable == null)
38 Reject(new Exception("The promise or task are expected"));
39 Reject(new Exception("The promise or task are expected"));
39 if (thenable == m_promise)
40 if (thenable == m_promise)
40 Reject(new Exception("The promise cannot be resolved with oneself"));
41 Reject(new Exception("The promise cannot be resolved with oneself"));
41
42
42 try {
43 try {
43 thenable.Then(this);
44 thenable.Then(this);
44 } catch (Exception err) {
45 } catch (Exception err) {
45 Reject(err);
46 Reject(err);
46 }
47 }
47 }
48 }
49
50 public virtual void Resolve(Task<T> thenable) {
51 if (thenable == null)
52 Reject(new Exception("The promise or task are expected"));
53
54 try {
55 thenable.Then(this);
56 } catch (Exception err) {
57 Reject(err);
58 }
59 }
48 }
60 }
49 } No newline at end of file
61 }
@@ -1,76 +1,70
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Threading.Tasks;
5 using System.Threading.Tasks;
6
6
7 namespace Implab.Formats.Json {
7 namespace Implab.Formats.Json {
8 public class JsonStringScanner : JsonScanner {
8 public class JsonStringScanner : JsonScanner {
9 const int _defaultBuffer = 64;
9 const int _defaultBuffer = 64;
10
10
11 readonly string m_data;
11 readonly string m_data;
12 int m_offset;
12 int m_offset;
13
13
14 JsonStringScanner(string data, char[] buffer, int pos, int length, int offset) : base(buffer, pos, length) {
14 JsonStringScanner(string data, char[] buffer, int pos, int length, int offset) : base(buffer, pos, length) {
15 m_data = data;
15 m_data = data;
16 m_offset = offset;
16 m_offset = offset;
17 }
17 }
18
18
19 protected override int Read(char[] buffer, int offset, int size) {
19 protected override int Read(char[] buffer, int offset, int size) {
20 if (m_data == null)
20 if (m_data == null)
21 return 0;
21 return 0;
22 if (m_offset >= m_data.Length)
22 if (m_offset >= m_data.Length)
23 return 0;
23 return 0;
24
24
25 var count = Math.Min(size, m_data.Length - m_offset);
25 var count = Math.Min(size, m_data.Length - m_offset);
26
26
27 m_data.CopyTo(m_offset, buffer, offset, count);
27 m_data.CopyTo(m_offset, buffer, offset, count);
28 m_offset += count;
28 m_offset += count;
29
29
30 return count;
30 return count;
31 }
31 }
32
32
33 public static JsonStringScanner Create(string data) {
33 public static JsonStringScanner Create(string data) {
34 Safe.ArgumentNotNull(data, nameof(data));
34 Safe.ArgumentNotNull(data, nameof(data));
35
35
36 if (data.Length <= _defaultBuffer)
36 if (data.Length <= _defaultBuffer)
37 return new JsonStringScanner(null, data.ToCharArray(), 0, data.Length, data.Length);
37 return new JsonStringScanner(null, data.ToCharArray(), 0, data.Length, data.Length);
38
38
39 var buffer = new char[_defaultBuffer];
39 var buffer = new char[_defaultBuffer];
40 data.CopyTo(0, buffer, 0, _defaultBuffer);
40 data.CopyTo(0, buffer, 0, _defaultBuffer);
41 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, _defaultBuffer);
41 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, _defaultBuffer);
42 }
42 }
43
43
44 public static JsonStringScanner Create(string data, int offset, int length) {
44 public static JsonStringScanner Create(string data, int offset, int length) {
45 Safe.ArgumentNotNull(data, nameof(data));
45 Safe.ArgumentNotNull(data, nameof(data));
46 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
46 Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset));
47 Safe.ArgumentGreaterThan(length, 0, nameof(length));
47 Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length));
48
49 if (offset + length > data.Length)
50 throw new ArgumentOutOfRangeException("Specified offset and length are out of the string bounds");
51
48
52 if (length <= _defaultBuffer) {
49 if (length <= _defaultBuffer) {
53 var buffer = new char[length];
50 var buffer = new char[length];
54 data.CopyTo(offset, buffer, 0, length);
51 data.CopyTo(offset, buffer, 0, length);
55
52
56 return new JsonStringScanner(null, buffer, 0, length, length);
53 return new JsonStringScanner(null, buffer, 0, length, length);
57 } else {
54 } else {
58 var buffer = new char[_defaultBuffer];
55 var buffer = new char[_defaultBuffer];
59 data.CopyTo(offset, buffer, 0, _defaultBuffer);
56 data.CopyTo(offset, buffer, 0, _defaultBuffer);
60 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, offset + _defaultBuffer);
57 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, offset + _defaultBuffer);
61 }
58 }
62 }
59 }
63
60
64 public static JsonStringScanner Create(char[] data, int offset, int length) {
61 public static JsonStringScanner Create(char[] data, int offset, int length) {
65 Safe.ArgumentNotNull(data, nameof(data));
62 Safe.ArgumentNotNull(data, nameof(data));
66 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
63 Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset));
67 Safe.ArgumentGreaterThan(length, 0, nameof(length));
64 Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length));
68
69 if (offset + length > data.Length)
70 throw new ArgumentOutOfRangeException("Specified offset and length are out of the array bounds");
71
65
72 return new JsonStringScanner(null, data, offset, offset + length, offset + length);
66 return new JsonStringScanner(null, data, offset, offset + length, offset + length);
73
67
74 }
68 }
75 }
69 }
76 }
70 }
@@ -1,10 +1,12
1 using System.Threading;
1 using System.Threading;
2 using System.Threading.Tasks;
2 using System.Threading.Tasks;
3
3
4 namespace Implab.Messaging {
4 namespace Implab.Messaging {
5 public interface IConsumer<T> {
5 public interface IConsumer<T> {
6 Task<T> Receive(CancellationToken ct);
6 T Receive(CancellationToken ct);
7
8 Task<T> ReceiveAsync(CancellationToken ct);
7
9
8 bool TryReceive(out T message);
10 bool TryReceive(out T message);
9 }
11 }
10 } No newline at end of file
12 }
@@ -1,11 +1,15
1 using System.Collections.Generic;
1 using System.Collections.Generic;
2 using System.Threading;
2 using System.Threading;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4
4
5 namespace Implab.Messaging {
5 namespace Implab.Messaging {
6 public interface IProducer<T> {
6 public interface IProducer<T> {
7 void PostMessage(T message, CancellationToken ct);
8
7 Task PostMessageAsync(T message, CancellationToken ct);
9 Task PostMessageAsync(T message, CancellationToken ct);
8
10
11 void PostMessages(IEnumerable<T> messages, CancellationToken ct);
12
9 Task PostMessagesAsync(IEnumerable<T> messages, CancellationToken ct);
13 Task PostMessagesAsync(IEnumerable<T> messages, CancellationToken ct);
10 }
14 }
11 } No newline at end of file
15 }
@@ -1,101 +1,101
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3
3
4 namespace Implab.Parallels {
4 namespace Implab.Parallels {
5 public class BlockingQueue<T> : AsyncQueue<T> {
5 public class BlockingQueue<T> : AsyncQueue<T> {
6 readonly object m_lock = new object();
6 readonly object m_lock = new object();
7
7
8 public void EnqueuePulse(T value) {
8 public void EnqueuePulse(T value) {
9 base.Enqueue(value);
9 base.Enqueue(value);
10 lock (m_lock)
10 lock (m_lock)
11 Monitor.Pulse(m_lock);
11 Monitor.Pulse(m_lock);
12 }
12 }
13
13
14 public void EnqueueRangePulse(T[] data, int offset, int length) {
14 public void EnqueueRangePulse(T[] data, int offset, int length) {
15 base.EnqueueRange(data, offset, length);
15 base.EnqueueRange(data, offset, length);
16 if (length > 1)
16 if (length > 1)
17 lock (m_lock)
17 lock (m_lock)
18 Monitor.PulseAll(m_lock);
18 Monitor.PulseAll(m_lock);
19 else
19 else
20 lock (m_lock)
20 lock (m_lock)
21 Monitor.Pulse(m_lock);
21 Monitor.Pulse(m_lock);
22 }
22 }
23
23
24 public T GetItem(int timeout) {
24 public T GetItem(int timeout) {
25 T item;
25 T item;
26
26
27 if (!TryDequeue(out item)) {
27 if (!TryDequeue(out item)) {
28 var t1 = Environment.TickCount;
28 var t1 = Environment.TickCount;
29 var dt = timeout;
29 var dt = timeout;
30
30
31 lock (m_lock) {
31 lock (m_lock) {
32 while (!TryDequeue(out item)) {
32 while (!TryDequeue(out item)) {
33 if (!Monitor.Wait(m_lock, dt))
33 if (!Monitor.Wait(m_lock, dt))
34 throw new TimeoutException();
34 throw new TimeoutException();
35 if (timeout >= 0) {
35 if (timeout >= 0) {
36 dt = timeout - Environment.TickCount + t1;
36 dt = timeout - Environment.TickCount + t1;
37 if (dt < 0)
37 if (dt < 0)
38 throw new TimeoutException();
38 throw new TimeoutException();
39 }
39 }
40 }
40 }
41 }
41 }
42 }
42 }
43 return item;
43 return item;
44 }
44 }
45
45
46 public T GetItem() {
46 public T GetItem() {
47 T item;
47 T item;
48 if (!TryDequeue(out item))
48 if (!TryDequeue(out item))
49 lock (m_lock) {
49 lock (m_lock) {
50 while (!TryDequeue(out item))
50 while (!TryDequeue(out item))
51 Monitor.Wait(m_lock);
51 Monitor.Wait(m_lock);
52 }
52 }
53 return item;
53 return item;
54 }
54 }
55
55
56 public T[] GetRange(int max, int timeout) {
56 public T[] GetRange(int max, int timeout) {
57 Safe.ArgumentInRange(max, 1, Int32.MaxValue, "max");
57 Safe.ArgumentInRange(max > 0 , nameof(max));
58
58
59 var buffer = new T[max];
59 var buffer = new T[max];
60 int actual;
60 int actual;
61 if (!TryDequeueRange(buffer, 0, max, out actual)) {
61 if (!TryDequeueRange(buffer, 0, max, out actual)) {
62 var t1 = Environment.TickCount;
62 var t1 = Environment.TickCount;
63 var dt = timeout;
63 var dt = timeout;
64
64
65 lock (m_lock) {
65 lock (m_lock) {
66 while (!TryDequeueRange(buffer, 0, max, out actual)) {
66 while (!TryDequeueRange(buffer, 0, max, out actual)) {
67
67
68 if (!Monitor.Wait(m_lock, dt))
68 if (!Monitor.Wait(m_lock, dt))
69 throw new TimeoutException();
69 throw new TimeoutException();
70
70
71 if (timeout >= 0) {
71 if (timeout >= 0) {
72 dt = timeout - Environment.TickCount + t1;
72 dt = timeout - Environment.TickCount + t1;
73 if (dt < 0)
73 if (dt < 0)
74 throw new TimeoutException();
74 throw new TimeoutException();
75 }
75 }
76 }
76 }
77 }
77 }
78 }
78 }
79
79
80 var data = new T[actual];
80 var data = new T[actual];
81 Array.Copy(buffer, data, actual);
81 Array.Copy(buffer, data, actual);
82 return data;
82 return data;
83 }
83 }
84
84
85 public T[] GetRange(int max) {
85 public T[] GetRange(int max) {
86 Safe.ArgumentInRange(max, 1, Int32.MaxValue, "max");
86 Safe.ArgumentInRange(max > 0, nameof(max));
87
87
88 var buffer = new T[max];
88 var buffer = new T[max];
89 int actual;
89 int actual;
90 if (!TryDequeueRange(buffer, 0, max, out actual))
90 if (!TryDequeueRange(buffer, 0, max, out actual))
91 lock (m_lock)
91 lock (m_lock)
92 while (!TryDequeueRange(buffer, 0, max, out actual))
92 while (!TryDequeueRange(buffer, 0, max, out actual))
93 Monitor.Wait(m_lock);
93 Monitor.Wait(m_lock);
94
94
95 var data = new T[actual];
95 var data = new T[actual];
96 Array.Copy(buffer, data, actual);
96 Array.Copy(buffer, data, actual);
97 return data;
97 return data;
98 }
98 }
99 }
99 }
100 }
100 }
101
101
@@ -1,164 +1,171
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Text.RegularExpressions;
5 using System.Text.RegularExpressions;
6 using System.Diagnostics;
6 using System.Diagnostics;
7 using System.Collections;
7 using System.Collections;
8 using System.Runtime.CompilerServices;
8 using System.Runtime.CompilerServices;
9 using System.Threading.Tasks;
9
10
10 #if NET_4_5
11 #if NET_4_5
11 using System.Threading.Tasks;
12 using System.Threading.Tasks;
12 #endif
13 #endif
13
14
14 namespace Implab
15 namespace Implab
15 {
16 {
16 public static class Safe
17 public static class Safe
17 {
18 {
18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 [MethodImpl(MethodImplOptions.AggressiveInlining)]
19 public static void ArgumentAssert(bool condition, string paramName) {
20 public static void ArgumentAssert(bool condition, string paramName) {
20 if (!condition)
21 if (!condition)
21 throw new ArgumentException("The parameter is invalid", paramName);
22 throw new ArgumentException("The parameter is invalid", paramName);
22 }
23 }
23
24
24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 [MethodImpl(MethodImplOptions.AggressiveInlining)]
25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
26 public static void ArgumentMatch(string value, string paramName, Regex rx) {
26 if (rx == null)
27 if (rx == null)
27 throw new ArgumentNullException("rx");
28 throw new ArgumentNullException("rx");
28 if (!rx.IsMatch(value))
29 if (!rx.IsMatch(value))
29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
30 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
30 }
31 }
31
32
32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 [MethodImpl(MethodImplOptions.AggressiveInlining)]
33 public static void ArgumentNotEmpty(string value, string paramName) {
34 public static void ArgumentNotEmpty(string value, string paramName) {
34 if (String.IsNullOrEmpty(value))
35 if (String.IsNullOrEmpty(value))
35 throw new ArgumentException("The parameter can't be empty", paramName);
36 throw new ArgumentException("The parameter can't be empty", paramName);
36 }
37 }
37
38
38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
40 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
40 if (value == null || value.Length == 0)
41 if (value == null || value.Length == 0)
41 throw new ArgumentException("The array must be not emty", paramName);
42 throw new ArgumentException("The array must be not emty", paramName);
42 }
43 }
43
44
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 [MethodImpl(MethodImplOptions.AggressiveInlining)]
45 public static void ArgumentNotNull(object value, string paramName) {
46 public static void ArgumentNotNull(object value, string paramName) {
46 if (value == null)
47 if (value == null)
47 throw new ArgumentNullException(paramName);
48 throw new ArgumentNullException(paramName);
48 }
49 }
49
50
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
52 internal static void ArgumentGreaterEqThan(int value, int min, string paramName) {
52 if (value < min)
53 if (value < min)
53 throw new ArgumentOutOfRangeException(paramName);
54 throw new ArgumentOutOfRangeException(paramName);
54 }
55 }
55
56
56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 [MethodImpl(MethodImplOptions.AggressiveInlining)]
57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
58 public static void ArgumentInRange(bool condition, string paramName) {
58 if (value < min || value > max)
59 if (!condition)
59 throw new ArgumentOutOfRangeException(paramName);
60 throw new ArgumentOutOfRangeException(paramName);
60 }
61 }
61
62
62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 [MethodImpl(MethodImplOptions.AggressiveInlining)]
63 public static void ArgumentOfType(object value, Type type, string paramName) {
64 public static void ArgumentOfType(object value, Type type, string paramName) {
64 if (!type.IsInstanceOfType(value))
65 if (!type.IsInstanceOfType(value))
65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
66 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
66 }
67 }
67
68
68 public static void Dispose(params IDisposable[] objects) {
69 public static void Dispose(params IDisposable[] objects) {
69 foreach (var d in objects)
70 foreach (var d in objects)
70 if (d != null)
71 if (d != null)
71 d.Dispose();
72 d.Dispose();
72 }
73 }
73
74
74 public static void Dispose(params object[] objects) {
75 public static void Dispose(params object[] objects) {
75 foreach (var obj in objects) {
76 foreach (var obj in objects) {
76 var d = obj as IDisposable;
77 var d = obj as IDisposable;
77 if (d != null)
78 if (d != null)
78 d.Dispose();
79 d.Dispose();
79 }
80 }
80 }
81 }
81
82
82 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
83 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
83 foreach (var d in objects)
84 foreach (var d in objects)
84 Dispose(d);
85 Dispose(d);
85 }
86 }
86
87
87 public static void DisposeCollection(IEnumerable objects) {
88 public static void DisposeCollection(IEnumerable objects) {
88 foreach (var d in objects)
89 foreach (var d in objects)
89 Dispose(d);
90 Dispose(d);
90 }
91 }
91
92
92 public static void Dispose(object obj) {
93 public static void Dispose(object obj) {
93 if (obj is IDisposable)
94 if (obj is IDisposable)
94 Dispose((IDisposable)obj);
95 Dispose((IDisposable)obj);
95
96
96 }
97 }
97
98
98 [DebuggerStepThrough]
99 [DebuggerStepThrough]
99 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
100 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
100 if (handler != null)
101 if (handler != null)
101 handler(sender, args);
102 handler(sender, args);
102 }
103 }
103
104
104 [DebuggerStepThrough]
105 [DebuggerStepThrough]
105 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
106 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
106 if (handler != null)
107 if (handler != null)
107 handler(sender, args);
108 handler(sender, args);
108 }
109 }
109
110
110 [DebuggerStepThrough]
111 [DebuggerStepThrough]
111 public static IPromise<T> Run<T>(Func<T> action) {
112 public static IPromise<T> Run<T>(Func<T> action) {
112 ArgumentNotNull(action, "action");
113 ArgumentNotNull(action, "action");
113
114
114 try {
115 try {
115 return Promise.Resolve(action());
116 return Promise.Resolve(action());
116 } catch (Exception err) {
117 } catch (Exception err) {
117 return Promise.Reject<T>(err);
118 return Promise.Reject<T>(err);
118 }
119 }
119 }
120 }
120
121
121 [DebuggerStepThrough]
122 [DebuggerStepThrough]
122 public static IPromise Run(Action action) {
123 public static IPromise Run(Action action) {
123 ArgumentNotNull(action, "action");
124 ArgumentNotNull(action, "action");
124
125
125 try {
126 try {
126 action();
127 action();
127 return Promise.Resolve();
128 return Promise.Resolve();
128 } catch (Exception err) {
129 } catch (Exception err) {
129 return Promise.Reject(err);
130 return Promise.Reject(err);
130 }
131 }
131 }
132 }
132
133
133 [DebuggerStepThrough]
134 [DebuggerStepThrough]
134 public static IPromise Run(Func<IPromise> action) {
135 public static IPromise Run(Func<IPromise> action) {
135 ArgumentNotNull(action, "action");
136 ArgumentNotNull(action, "action");
136
137
137 try {
138 try {
138 return action() ?? Promise.Reject(new Exception("The action returned null"));
139 return action() ?? Promise.Reject(new Exception("The action returned null"));
139 } catch (Exception err) {
140 } catch (Exception err) {
140 return Promise.Reject(err);
141 return Promise.Reject(err);
141 }
142 }
142 }
143 }
143
144
144 public static void NoWait(IPromise promise) {
145 public static void NoWait(IPromise promise) {
145 }
146 }
146
147
148 public static void NoWait(Task promise) {
149 }
150
151 public static void NoWait<T>(Task<T> promise) {
152 }
153
147 [DebuggerStepThrough]
154 [DebuggerStepThrough]
148 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
155 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
149 ArgumentNotNull(action, "action");
156 ArgumentNotNull(action, "action");
150
157
151 try {
158 try {
152 return action() ?? Promise.Reject<T>(new Exception("The action returned null"));
159 return action() ?? Promise.Reject<T>(new Exception("The action returned null"));
153 } catch (Exception err) {
160 } catch (Exception err) {
154 return Promise.Reject<T>(err);
161 return Promise.Reject<T>(err);
155 }
162 }
156 }
163 }
157
164
158 #if NET_4_5
165 #if NET_4_5
159 public static void NoWait(Task t) {
166 public static void NoWait(Task t) {
160 }
167 }
161 #endif
168 #endif
162
169
163 }
170 }
164 }
171 }
@@ -1,610 +1,610
1 using Implab.Formats.Json;
1 using Implab.Formats.Json;
2 using System;
2 using System;
3 using System.Collections.Generic;
3 using System.Collections.Generic;
4 using System.Globalization;
4 using System.Globalization;
5 using System.Linq;
5 using System.Linq;
6 using System.Xml;
6 using System.Xml;
7
7
8 namespace Implab.Xml {
8 namespace Implab.Xml {
9 public class JsonXmlReader : XmlReader {
9 public class JsonXmlReader : XmlReader {
10 struct JsonContext {
10 struct JsonContext {
11 public string localName;
11 public string localName;
12 public bool skip;
12 public bool skip;
13 }
13 }
14
14
15 JsonReader m_parser;
15 JsonReader m_parser;
16 JsonXmlReaderOptions m_options;
16 JsonXmlReaderOptions m_options;
17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
18 XmlNameTable m_nameTable;
18 XmlNameTable m_nameTable;
19
19
20 readonly string m_jsonRootName;
20 readonly string m_jsonRootName;
21 readonly string m_jsonNamespace;
21 readonly string m_jsonNamespace;
22 readonly string m_jsonPrefix;
22 readonly string m_jsonPrefix;
23 readonly bool m_jsonFlattenArrays;
23 readonly bool m_jsonFlattenArrays;
24 readonly string m_jsonArrayItemName;
24 readonly string m_jsonArrayItemName;
25
25
26 string m_jsonLocalName;
26 string m_jsonLocalName;
27 string m_jsonValueName;
27 string m_jsonValueName;
28 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
28 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
29
29
30 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
30 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
31
31
32 XmlQualifiedName m_elementQName;
32 XmlQualifiedName m_elementQName;
33 string m_elementPrefix;
33 string m_elementPrefix;
34 int m_elementDepth;
34 int m_elementDepth;
35 bool m_elementIsEmpty;
35 bool m_elementIsEmpty;
36
36
37 XmlQualifiedName m_qName;
37 XmlQualifiedName m_qName;
38 string m_prefix;
38 string m_prefix;
39 int m_xmlDepth;
39 int m_xmlDepth;
40
40
41 XmlSimpleAttribute[] m_attributes;
41 XmlSimpleAttribute[] m_attributes;
42 string m_value;
42 string m_value;
43 bool m_isEmpty;
43 bool m_isEmpty;
44
44
45 XmlNodeType m_nodeType = XmlNodeType.None;
45 XmlNodeType m_nodeType = XmlNodeType.None;
46
46
47 bool m_isAttribute; // indicates that we are reading attribute nodes
47 bool m_isAttribute; // indicates that we are reading attribute nodes
48 int m_currentAttribute;
48 int m_currentAttribute;
49 bool m_currentAttributeRead;
49 bool m_currentAttributeRead;
50
50
51
51
52 XmlNameContext m_context;
52 XmlNameContext m_context;
53
53
54 readonly string m_xmlnsPrefix;
54 readonly string m_xmlnsPrefix;
55 readonly string m_xmlnsNamespace;
55 readonly string m_xmlnsNamespace;
56 readonly string m_xsiPrefix;
56 readonly string m_xsiPrefix;
57 readonly string m_xsiNamespace;
57 readonly string m_xsiNamespace;
58
58
59
59
60 public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) {
60 public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) {
61 Safe.ArgumentNotNull(parser, nameof(parser));
61 Safe.ArgumentNotNull(parser, nameof(parser));
62 m_parser = parser;
62 m_parser = parser;
63
63
64 m_options = options ?? new JsonXmlReaderOptions();
64 m_options = options ?? new JsonXmlReaderOptions();
65
65
66 m_jsonFlattenArrays = m_options.FlattenArrays;
66 m_jsonFlattenArrays = m_options.FlattenArrays;
67 m_nameTable = m_options.NameTable ?? new NameTable();
67 m_nameTable = m_options.NameTable ?? new NameTable();
68
68
69 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
69 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
70 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
70 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
71 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
71 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
72 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
72 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
73 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
73 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
74 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
74 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
75 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
75 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
76 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
76 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
77
77
78 // TODO validate m_jsonRootName, m_jsonArrayItemName
78 // TODO validate m_jsonRootName, m_jsonArrayItemName
79
79
80 m_context = new XmlNameContext(null, 0);
80 m_context = new XmlNameContext(null, 0);
81 }
81 }
82
82
83 public override int AttributeCount {
83 public override int AttributeCount {
84 get {
84 get {
85 return m_attributes == null ? 0 : m_attributes.Length;
85 return m_attributes == null ? 0 : m_attributes.Length;
86 }
86 }
87 }
87 }
88
88
89 public override string BaseURI {
89 public override string BaseURI {
90 get {
90 get {
91 return string.Empty;
91 return string.Empty;
92 }
92 }
93 }
93 }
94
94
95 public override int Depth {
95 public override int Depth {
96 get {
96 get {
97 return m_xmlDepth;
97 return m_xmlDepth;
98 }
98 }
99 }
99 }
100
100
101 public override bool EOF {
101 public override bool EOF {
102 get {
102 get {
103 return m_position == JsonXmlReaderPosition.Eof;
103 return m_position == JsonXmlReaderPosition.Eof;
104 }
104 }
105 }
105 }
106
106
107 public override bool IsEmptyElement {
107 public override bool IsEmptyElement {
108 get { return m_isEmpty; }
108 get { return m_isEmpty; }
109 }
109 }
110
110
111
111
112 public override string LocalName {
112 public override string LocalName {
113 get {
113 get {
114 return m_qName.Name;
114 return m_qName.Name;
115 }
115 }
116 }
116 }
117
117
118 public override string NamespaceURI {
118 public override string NamespaceURI {
119 get {
119 get {
120 return m_qName.Namespace;
120 return m_qName.Namespace;
121 }
121 }
122 }
122 }
123
123
124 public override XmlNameTable NameTable {
124 public override XmlNameTable NameTable {
125 get {
125 get {
126 return m_nameTable;
126 return m_nameTable;
127 }
127 }
128 }
128 }
129
129
130 public override XmlNodeType NodeType {
130 public override XmlNodeType NodeType {
131 get {
131 get {
132 return m_nodeType;
132 return m_nodeType;
133 }
133 }
134 }
134 }
135
135
136 public override string Prefix {
136 public override string Prefix {
137 get {
137 get {
138 return m_prefix;
138 return m_prefix;
139 }
139 }
140 }
140 }
141
141
142 public override ReadState ReadState {
142 public override ReadState ReadState {
143 get {
143 get {
144 switch (m_position) {
144 switch (m_position) {
145 case JsonXmlReaderPosition.Initial:
145 case JsonXmlReaderPosition.Initial:
146 return ReadState.Initial;
146 return ReadState.Initial;
147 case JsonXmlReaderPosition.Eof:
147 case JsonXmlReaderPosition.Eof:
148 return ReadState.EndOfFile;
148 return ReadState.EndOfFile;
149 case JsonXmlReaderPosition.Closed:
149 case JsonXmlReaderPosition.Closed:
150 return ReadState.Closed;
150 return ReadState.Closed;
151 case JsonXmlReaderPosition.Error:
151 case JsonXmlReaderPosition.Error:
152 return ReadState.Error;
152 return ReadState.Error;
153 default:
153 default:
154 return ReadState.Interactive;
154 return ReadState.Interactive;
155 };
155 };
156 }
156 }
157 }
157 }
158
158
159 public override string Value {
159 public override string Value {
160 get {
160 get {
161 return m_value;
161 return m_value;
162 }
162 }
163 }
163 }
164
164
165 public override string GetAttribute(int i) {
165 public override string GetAttribute(int i) {
166 Safe.ArgumentInRange(i, 0, AttributeCount - 1, nameof(i));
166 Safe.ArgumentInRange(i >= 0 && i < AttributeCount, nameof(i));
167 return m_attributes[i].Value;
167 return m_attributes[i].Value;
168 }
168 }
169
169
170 public override string GetAttribute(string name) {
170 public override string GetAttribute(string name) {
171 if (m_attributes == null)
171 if (m_attributes == null)
172 return null;
172 return null;
173 var qName = m_context.Resolve(name);
173 var qName = m_context.Resolve(name);
174 var attr = Array.Find(m_attributes, x => x.QName == qName);
174 var attr = Array.Find(m_attributes, x => x.QName == qName);
175 var value = attr?.Value;
175 var value = attr?.Value;
176 return value == string.Empty ? null : value;
176 return value == string.Empty ? null : value;
177 }
177 }
178
178
179 public override string GetAttribute(string name, string namespaceURI) {
179 public override string GetAttribute(string name, string namespaceURI) {
180 if (m_attributes == null)
180 if (m_attributes == null)
181 return null;
181 return null;
182 var qName = new XmlQualifiedName(name, namespaceURI);
182 var qName = new XmlQualifiedName(name, namespaceURI);
183 var attr = Array.Find(m_attributes, x => x.QName == qName);
183 var attr = Array.Find(m_attributes, x => x.QName == qName);
184 var value = attr?.Value;
184 var value = attr?.Value;
185 return value == string.Empty ? null : value;
185 return value == string.Empty ? null : value;
186 }
186 }
187
187
188 public override string LookupNamespace(string prefix) {
188 public override string LookupNamespace(string prefix) {
189 return m_context.ResolvePrefix(prefix);
189 return m_context.ResolvePrefix(prefix);
190 }
190 }
191
191
192 public override bool MoveToAttribute(string name) {
192 public override bool MoveToAttribute(string name) {
193 if (m_attributes == null || m_attributes.Length == 0)
193 if (m_attributes == null || m_attributes.Length == 0)
194 return false;
194 return false;
195
195
196 var qName = m_context.Resolve(name);
196 var qName = m_context.Resolve(name);
197 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
197 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
198 if (index >= 0) {
198 if (index >= 0) {
199 MoveToAttributeImpl(index);
199 MoveToAttributeImpl(index);
200 return true;
200 return true;
201 }
201 }
202 return false;
202 return false;
203 }
203 }
204
204
205 public override bool MoveToAttribute(string name, string ns) {
205 public override bool MoveToAttribute(string name, string ns) {
206 if (m_attributes == null || m_attributes.Length == 0)
206 if (m_attributes == null || m_attributes.Length == 0)
207 return false;
207 return false;
208
208
209 var qName = m_context.Resolve(name);
209 var qName = m_context.Resolve(name);
210 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
210 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
211 if (index >= 0) {
211 if (index >= 0) {
212 MoveToAttributeImpl(index);
212 MoveToAttributeImpl(index);
213 return true;
213 return true;
214 }
214 }
215 return false;
215 return false;
216 }
216 }
217
217
218 void MoveToAttributeImpl(int i) {
218 void MoveToAttributeImpl(int i) {
219 if (!m_isAttribute) {
219 if (!m_isAttribute) {
220 m_elementQName = m_qName;
220 m_elementQName = m_qName;
221 m_elementDepth = m_xmlDepth;
221 m_elementDepth = m_xmlDepth;
222 m_elementPrefix = m_prefix;
222 m_elementPrefix = m_prefix;
223 m_elementIsEmpty = m_isEmpty;
223 m_elementIsEmpty = m_isEmpty;
224 m_isAttribute = true;
224 m_isAttribute = true;
225 }
225 }
226
226
227 var attr = m_attributes[i];
227 var attr = m_attributes[i];
228
228
229
229
230 m_currentAttribute = i;
230 m_currentAttribute = i;
231 m_currentAttributeRead = false;
231 m_currentAttributeRead = false;
232 m_nodeType = XmlNodeType.Attribute;
232 m_nodeType = XmlNodeType.Attribute;
233
233
234 m_xmlDepth = m_elementDepth + 1;
234 m_xmlDepth = m_elementDepth + 1;
235 m_qName = attr.QName;
235 m_qName = attr.QName;
236 m_value = attr.Value;
236 m_value = attr.Value;
237 m_prefix = attr.Prefix;
237 m_prefix = attr.Prefix;
238 }
238 }
239
239
240 public override bool MoveToElement() {
240 public override bool MoveToElement() {
241 if (m_isAttribute) {
241 if (m_isAttribute) {
242 m_value = null;
242 m_value = null;
243 m_nodeType = XmlNodeType.Element;
243 m_nodeType = XmlNodeType.Element;
244 m_xmlDepth = m_elementDepth;
244 m_xmlDepth = m_elementDepth;
245 m_prefix = m_elementPrefix;
245 m_prefix = m_elementPrefix;
246 m_qName = m_elementQName;
246 m_qName = m_elementQName;
247 m_isEmpty = m_elementIsEmpty;
247 m_isEmpty = m_elementIsEmpty;
248 m_isAttribute = false;
248 m_isAttribute = false;
249 return true;
249 return true;
250 }
250 }
251 return false;
251 return false;
252 }
252 }
253
253
254 public override bool MoveToFirstAttribute() {
254 public override bool MoveToFirstAttribute() {
255 if (m_attributes != null && m_attributes.Length > 0) {
255 if (m_attributes != null && m_attributes.Length > 0) {
256 MoveToAttributeImpl(0);
256 MoveToAttributeImpl(0);
257 return true;
257 return true;
258 }
258 }
259 return false;
259 return false;
260 }
260 }
261
261
262 public override bool MoveToNextAttribute() {
262 public override bool MoveToNextAttribute() {
263 if (m_isAttribute) {
263 if (m_isAttribute) {
264 var next = m_currentAttribute + 1;
264 var next = m_currentAttribute + 1;
265 if (next < AttributeCount) {
265 if (next < AttributeCount) {
266 MoveToAttributeImpl(next);
266 MoveToAttributeImpl(next);
267 return true;
267 return true;
268 }
268 }
269 return false;
269 return false;
270 } else {
270 } else {
271 return MoveToFirstAttribute();
271 return MoveToFirstAttribute();
272 }
272 }
273
273
274 }
274 }
275
275
276 public override bool ReadAttributeValue() {
276 public override bool ReadAttributeValue() {
277 if (!m_isAttribute || m_currentAttributeRead)
277 if (!m_isAttribute || m_currentAttributeRead)
278 return false;
278 return false;
279
279
280 ValueNode(m_attributes[m_currentAttribute].Value);
280 ValueNode(m_attributes[m_currentAttribute].Value);
281 m_currentAttributeRead = true;
281 m_currentAttributeRead = true;
282 return true;
282 return true;
283 }
283 }
284
284
285 public override void ResolveEntity() {
285 public override void ResolveEntity() {
286 /* do nothing */
286 /* do nothing */
287 }
287 }
288
288
289 /// <summary>
289 /// <summary>
290 /// Determines do we need to increase depth after the current node
290 /// Determines do we need to increase depth after the current node
291 /// </summary>
291 /// </summary>
292 /// <returns></returns>
292 /// <returns></returns>
293 public bool IsSibling() {
293 public bool IsSibling() {
294 switch (m_nodeType) {
294 switch (m_nodeType) {
295 case XmlNodeType.None: // start document
295 case XmlNodeType.None: // start document
296 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
296 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
297 return false;
297 return false;
298 case XmlNodeType.Element:
298 case XmlNodeType.Element:
299 // if the elemnt is empty the next element will be it's sibling
299 // if the elemnt is empty the next element will be it's sibling
300 return m_isEmpty;
300 return m_isEmpty;
301 default:
301 default:
302 return true;
302 return true;
303 }
303 }
304 }
304 }
305
305
306 void ValueNode(string value) {
306 void ValueNode(string value) {
307 if (!IsSibling()) // the node is nested
307 if (!IsSibling()) // the node is nested
308 m_xmlDepth++;
308 m_xmlDepth++;
309
309
310 m_qName = XmlQualifiedName.Empty;
310 m_qName = XmlQualifiedName.Empty;
311 m_nodeType = XmlNodeType.Text;
311 m_nodeType = XmlNodeType.Text;
312 m_prefix = string.Empty;
312 m_prefix = string.Empty;
313 m_value = value;
313 m_value = value;
314 m_isEmpty = false;
314 m_isEmpty = false;
315 m_attributes = null;
315 m_attributes = null;
316 }
316 }
317
317
318 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
318 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
319 if (!IsSibling()) // the node is nested
319 if (!IsSibling()) // the node is nested
320 m_xmlDepth++;
320 m_xmlDepth++;
321
321
322 var context = m_context;
322 var context = m_context;
323 List<XmlSimpleAttribute> definedAttrs = null;
323 List<XmlSimpleAttribute> definedAttrs = null;
324
324
325 // define new namespaces
325 // define new namespaces
326 if (attrs != null) {
326 if (attrs != null) {
327 foreach (var attr in attrs) {
327 foreach (var attr in attrs) {
328 if (attr.QName.Name == "xmlns") {
328 if (attr.QName.Name == "xmlns") {
329 if (context == m_context)
329 if (context == m_context)
330 context = new XmlNameContext(m_context, m_xmlDepth);
330 context = new XmlNameContext(m_context, m_xmlDepth);
331 context.DefinePrefix(attr.Value, string.Empty);
331 context.DefinePrefix(attr.Value, string.Empty);
332 } else if (attr.Prefix == m_xmlnsPrefix) {
332 } else if (attr.Prefix == m_xmlnsPrefix) {
333 if (context == m_context)
333 if (context == m_context)
334 context = new XmlNameContext(m_context, m_xmlDepth);
334 context = new XmlNameContext(m_context, m_xmlDepth);
335 context.DefinePrefix(attr.Value, attr.QName.Name);
335 context.DefinePrefix(attr.Value, attr.QName.Name);
336 } else {
336 } else {
337 string attrPrefix;
337 string attrPrefix;
338 if (string.IsNullOrEmpty(attr.QName.Namespace))
338 if (string.IsNullOrEmpty(attr.QName.Namespace))
339 continue;
339 continue;
340
340
341 // auto-define prefixes
341 // auto-define prefixes
342 if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
342 if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
343 // new namespace prefix added
343 // new namespace prefix added
344 attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace);
344 attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace);
345 attr.Prefix = attrPrefix;
345 attr.Prefix = attrPrefix;
346
346
347 if (definedAttrs == null)
347 if (definedAttrs == null)
348 definedAttrs = new List<XmlSimpleAttribute>();
348 definedAttrs = new List<XmlSimpleAttribute>();
349
349
350 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
350 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
351 }
351 }
352 }
352 }
353 }
353 }
354 }
354 }
355
355
356 string p;
356 string p;
357 // auto-define prefixes
357 // auto-define prefixes
358 if (!context.LookupNamespacePrefix(ns, out p)) {
358 if (!context.LookupNamespacePrefix(ns, out p)) {
359 if (context == m_context)
359 if (context == m_context)
360 context = new XmlNameContext(m_context, m_xmlDepth);
360 context = new XmlNameContext(m_context, m_xmlDepth);
361 p = context.CreateNamespacePrefix(ns);
361 p = context.CreateNamespacePrefix(ns);
362 if (definedAttrs == null)
362 if (definedAttrs == null)
363 definedAttrs = new List<XmlSimpleAttribute>();
363 definedAttrs = new List<XmlSimpleAttribute>();
364
364
365 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
365 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
366 }
366 }
367
367
368 if (definedAttrs != null) {
368 if (definedAttrs != null) {
369 if (attrs != null)
369 if (attrs != null)
370 definedAttrs.AddRange(attrs);
370 definedAttrs.AddRange(attrs);
371 attrs = definedAttrs.ToArray();
371 attrs = definedAttrs.ToArray();
372 }
372 }
373
373
374 if (!empty)
374 if (!empty)
375 m_context = context;
375 m_context = context;
376
376
377 m_nodeType = XmlNodeType.Element;
377 m_nodeType = XmlNodeType.Element;
378 m_qName = new XmlQualifiedName(name, ns);
378 m_qName = new XmlQualifiedName(name, ns);
379 m_prefix = p;
379 m_prefix = p;
380 m_value = null;
380 m_value = null;
381 m_isEmpty = empty;
381 m_isEmpty = empty;
382 m_attributes = attrs;
382 m_attributes = attrs;
383 }
383 }
384
384
385 void EndElementNode(string name, string ns) {
385 void EndElementNode(string name, string ns) {
386 if (IsSibling()) {
386 if (IsSibling()) {
387 // closing the element which has children
387 // closing the element which has children
388 m_xmlDepth--;
388 m_xmlDepth--;
389 }
389 }
390
390
391 string p;
391 string p;
392 if (!m_context.LookupNamespacePrefix(ns, out p))
392 if (!m_context.LookupNamespacePrefix(ns, out p))
393 throw new Exception($"Failed to lookup namespace '{ns}'");
393 throw new Exception($"Failed to lookup namespace '{ns}'");
394
394
395 if (m_context.Depth == m_xmlDepth)
395 if (m_context.Depth == m_xmlDepth)
396 m_context = m_context.ParentContext;
396 m_context = m_context.ParentContext;
397
397
398 m_nodeType = XmlNodeType.EndElement;
398 m_nodeType = XmlNodeType.EndElement;
399 m_prefix = p;
399 m_prefix = p;
400 m_qName = new XmlQualifiedName(name, ns);
400 m_qName = new XmlQualifiedName(name, ns);
401 m_value = null;
401 m_value = null;
402 m_attributes = null;
402 m_attributes = null;
403 m_isEmpty = false;
403 m_isEmpty = false;
404 }
404 }
405
405
406 void XmlDeclaration() {
406 void XmlDeclaration() {
407 if (!IsSibling()) // the node is nested
407 if (!IsSibling()) // the node is nested
408 m_xmlDepth++;
408 m_xmlDepth++;
409 m_nodeType = XmlNodeType.XmlDeclaration;
409 m_nodeType = XmlNodeType.XmlDeclaration;
410 m_qName = new XmlQualifiedName("xml");
410 m_qName = new XmlQualifiedName("xml");
411 m_value = "version='1.0'";
411 m_value = "version='1.0'";
412 m_prefix = string.Empty;
412 m_prefix = string.Empty;
413 m_attributes = null;
413 m_attributes = null;
414 m_isEmpty = false;
414 m_isEmpty = false;
415 }
415 }
416
416
417 public override bool Read() {
417 public override bool Read() {
418 try {
418 try {
419 string elementName;
419 string elementName;
420 XmlSimpleAttribute[] elementAttrs = null;
420 XmlSimpleAttribute[] elementAttrs = null;
421 MoveToElement();
421 MoveToElement();
422
422
423 switch (m_position) {
423 switch (m_position) {
424 case JsonXmlReaderPosition.Initial:
424 case JsonXmlReaderPosition.Initial:
425 m_jsonLocalName = m_jsonRootName;
425 m_jsonLocalName = m_jsonRootName;
426 m_jsonSkip = false;
426 m_jsonSkip = false;
427 XmlDeclaration();
427 XmlDeclaration();
428 m_position = JsonXmlReaderPosition.Declaration;
428 m_position = JsonXmlReaderPosition.Declaration;
429 return true;
429 return true;
430 case JsonXmlReaderPosition.Declaration:
430 case JsonXmlReaderPosition.Declaration:
431 elementAttrs = new[] {
431 elementAttrs = new[] {
432 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
432 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
433 string.IsNullOrEmpty(m_jsonPrefix) ?
433 string.IsNullOrEmpty(m_jsonPrefix) ?
434 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
434 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
435 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
435 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
436 };
436 };
437 break;
437 break;
438 case JsonXmlReaderPosition.ValueElement:
438 case JsonXmlReaderPosition.ValueElement:
439 if (!m_isEmpty) {
439 if (!m_isEmpty) {
440 if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty))
440 if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty))
441 ValueNode(m_parser.ElementValue);
441 ValueNode(m_parser.ElementValue);
442 else
442 else
443 goto case JsonXmlReaderPosition.ValueContent;
443 goto case JsonXmlReaderPosition.ValueContent;
444 m_position = JsonXmlReaderPosition.ValueContent;
444 m_position = JsonXmlReaderPosition.ValueContent;
445 return true;
445 return true;
446 } else {
446 } else {
447 m_position = JsonXmlReaderPosition.ValueEndElement;
447 m_position = JsonXmlReaderPosition.ValueEndElement;
448 break;
448 break;
449 }
449 }
450 case JsonXmlReaderPosition.ValueContent:
450 case JsonXmlReaderPosition.ValueContent:
451 EndElementNode(m_jsonValueName, m_jsonNamespace);
451 EndElementNode(m_jsonValueName, m_jsonNamespace);
452 m_position = JsonXmlReaderPosition.ValueEndElement;
452 m_position = JsonXmlReaderPosition.ValueEndElement;
453 return true;
453 return true;
454 case JsonXmlReaderPosition.Eof:
454 case JsonXmlReaderPosition.Eof:
455 case JsonXmlReaderPosition.Closed:
455 case JsonXmlReaderPosition.Closed:
456 case JsonXmlReaderPosition.Error:
456 case JsonXmlReaderPosition.Error:
457 return false;
457 return false;
458 }
458 }
459
459
460 while (m_parser.Read()) {
460 while (m_parser.Read()) {
461 var jsonName = m_nameTable.Add(m_parser.ElementName);
461 var jsonName = m_nameTable.Add(m_parser.ElementName);
462
462
463 switch (m_parser.ElementType) {
463 switch (m_parser.ElementType) {
464 case JsonElementType.BeginObject:
464 case JsonElementType.BeginObject:
465 if (!EnterJsonObject(jsonName, out elementName))
465 if (!EnterJsonObject(jsonName, out elementName))
466 continue;
466 continue;
467
467
468 m_position = JsonXmlReaderPosition.BeginObject;
468 m_position = JsonXmlReaderPosition.BeginObject;
469 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
469 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
470 break;
470 break;
471 case JsonElementType.EndObject:
471 case JsonElementType.EndObject:
472 if (!LeaveJsonScope(out elementName))
472 if (!LeaveJsonScope(out elementName))
473 continue;
473 continue;
474
474
475 m_position = JsonXmlReaderPosition.EndObject;
475 m_position = JsonXmlReaderPosition.EndObject;
476 EndElementNode(elementName, m_jsonNamespace);
476 EndElementNode(elementName, m_jsonNamespace);
477 break;
477 break;
478 case JsonElementType.BeginArray:
478 case JsonElementType.BeginArray:
479 if (!EnterJsonArray(jsonName, out elementName))
479 if (!EnterJsonArray(jsonName, out elementName))
480 continue;
480 continue;
481
481
482 m_position = JsonXmlReaderPosition.BeginArray;
482 m_position = JsonXmlReaderPosition.BeginArray;
483 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
483 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
484 break;
484 break;
485 case JsonElementType.EndArray:
485 case JsonElementType.EndArray:
486 if (!LeaveJsonScope(out elementName))
486 if (!LeaveJsonScope(out elementName))
487 continue;
487 continue;
488
488
489 m_position = JsonXmlReaderPosition.EndArray;
489 m_position = JsonXmlReaderPosition.EndArray;
490 EndElementNode(elementName, m_jsonNamespace);
490 EndElementNode(elementName, m_jsonNamespace);
491 break;
491 break;
492 case JsonElementType.Value:
492 case JsonElementType.Value:
493 if (!VisitJsonValue(jsonName, out m_jsonValueName))
493 if (!VisitJsonValue(jsonName, out m_jsonValueName))
494 continue;
494 continue;
495
495
496 m_position = JsonXmlReaderPosition.ValueElement;
496 m_position = JsonXmlReaderPosition.ValueElement;
497 if (m_parser.ElementValue == null)
497 if (m_parser.ElementValue == null)
498 // generate empty element with xsi:nil="true" attribute
498 // generate empty element with xsi:nil="true" attribute
499 ElementNode(
499 ElementNode(
500 m_jsonValueName,
500 m_jsonValueName,
501 m_jsonNamespace,
501 m_jsonNamespace,
502 new[] {
502 new[] {
503 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, "true")
503 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, "true")
504 },
504 },
505 true
505 true
506 );
506 );
507 else
507 else
508 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty));
508 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty));
509 break;
509 break;
510 default:
510 default:
511 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
511 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
512 }
512 }
513 return true;
513 return true;
514 }
514 }
515
515
516 m_position = JsonXmlReaderPosition.Eof;
516 m_position = JsonXmlReaderPosition.Eof;
517 return false;
517 return false;
518 } catch {
518 } catch {
519 m_position = JsonXmlReaderPosition.Error;
519 m_position = JsonXmlReaderPosition.Error;
520 throw;
520 throw;
521 }
521 }
522 }
522 }
523
523
524 void SaveJsonName() {
524 void SaveJsonName() {
525 m_jsonNameStack.Push(new JsonContext {
525 m_jsonNameStack.Push(new JsonContext {
526 skip = m_jsonSkip,
526 skip = m_jsonSkip,
527 localName = m_jsonLocalName
527 localName = m_jsonLocalName
528 });
528 });
529
529
530 }
530 }
531
531
532 bool EnterJsonObject(string name, out string elementName) {
532 bool EnterJsonObject(string name, out string elementName) {
533 SaveJsonName();
533 SaveJsonName();
534 m_jsonSkip = false;
534 m_jsonSkip = false;
535
535
536 if (string.IsNullOrEmpty(name)) {
536 if (string.IsNullOrEmpty(name)) {
537 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
537 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
538 m_jsonLocalName = m_jsonArrayItemName;
538 m_jsonLocalName = m_jsonArrayItemName;
539 } else {
539 } else {
540 m_jsonLocalName = name;
540 m_jsonLocalName = name;
541 }
541 }
542
542
543 elementName = m_jsonLocalName;
543 elementName = m_jsonLocalName;
544 return true;
544 return true;
545 }
545 }
546
546
547 /// <summary>
547 /// <summary>
548 /// Called when JSON parser visits BeginArray ('[') element.
548 /// Called when JSON parser visits BeginArray ('[') element.
549 /// </summary>
549 /// </summary>
550 /// <param name="name">Optional property name if the array is the member of an object</param>
550 /// <param name="name">Optional property name if the array is the member of an object</param>
551 /// <returns>true if element should be emited, false otherwise</returns>
551 /// <returns>true if element should be emited, false otherwise</returns>
552 bool EnterJsonArray(string name, out string elementName) {
552 bool EnterJsonArray(string name, out string elementName) {
553 SaveJsonName();
553 SaveJsonName();
554
554
555 if (string.IsNullOrEmpty(name)) {
555 if (string.IsNullOrEmpty(name)) {
556 // m_jsonNameStack.Count == 1 means the root node
556 // m_jsonNameStack.Count == 1 means the root node
557 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
557 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
558 m_jsonLocalName = m_jsonArrayItemName;
558 m_jsonLocalName = m_jsonArrayItemName;
559
559
560 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
560 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
561 } else {
561 } else {
562 m_jsonLocalName = name;
562 m_jsonLocalName = name;
563 m_jsonSkip = m_jsonFlattenArrays;
563 m_jsonSkip = m_jsonFlattenArrays;
564 }
564 }
565 elementName = m_jsonLocalName;
565 elementName = m_jsonLocalName;
566
566
567 return !m_jsonSkip;
567 return !m_jsonSkip;
568 }
568 }
569
569
570 bool VisitJsonValue(string name, out string elementName) {
570 bool VisitJsonValue(string name, out string elementName) {
571 if (string.IsNullOrEmpty(name)) {
571 if (string.IsNullOrEmpty(name)) {
572 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
572 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
573 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
573 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
574 } else {
574 } else {
575 elementName = name;
575 elementName = name;
576 }
576 }
577 return true;
577 return true;
578 }
578 }
579
579
580 bool LeaveJsonScope(out string elementName) {
580 bool LeaveJsonScope(out string elementName) {
581 elementName = m_jsonLocalName;
581 elementName = m_jsonLocalName;
582 var skip = m_jsonSkip;
582 var skip = m_jsonSkip;
583
583
584 var prev = m_jsonNameStack.Pop();
584 var prev = m_jsonNameStack.Pop();
585 m_jsonLocalName = prev.localName;
585 m_jsonLocalName = prev.localName;
586 m_jsonSkip = prev.skip;
586 m_jsonSkip = prev.skip;
587
587
588 return !skip;
588 return !skip;
589 }
589 }
590
590
591 public override string ToString() {
591 public override string ToString() {
592 switch (NodeType) {
592 switch (NodeType) {
593 case XmlNodeType.Element:
593 case XmlNodeType.Element:
594 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{x.Value}'"))} {(IsEmptyElement ? "/" : "")}>";
594 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{x.Value}'"))} {(IsEmptyElement ? "/" : "")}>";
595 case XmlNodeType.Attribute:
595 case XmlNodeType.Attribute:
596 return $"@{Name}";
596 return $"@{Name}";
597 case XmlNodeType.Text:
597 case XmlNodeType.Text:
598 return $"{Value}";
598 return $"{Value}";
599 case XmlNodeType.CDATA:
599 case XmlNodeType.CDATA:
600 return $"<![CDATA[{Value}]]>";
600 return $"<![CDATA[{Value}]]>";
601 case XmlNodeType.EntityReference:
601 case XmlNodeType.EntityReference:
602 return $"&{Name};";
602 return $"&{Name};";
603 case XmlNodeType.EndElement:
603 case XmlNodeType.EndElement:
604 return $"</{Name}>";
604 return $"</{Name}>";
605 default:
605 default:
606 return $".{NodeType} {Name} {Value}";
606 return $".{NodeType} {Name} {Value}";
607 }
607 }
608 }
608 }
609 }
609 }
610 }
610 }
@@ -1,51 +1,65
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.IO;
3 using System.IO;
4 using System.Linq;
4 using System.Linq;
5 using System.Text;
5 using System.Text;
6 using System.Threading.Tasks;
6 using System.Threading.Tasks;
7 using System.Xml;
7 using System.Xml;
8 using System.Xml.Linq;
8 using System.Xml.Linq;
9
9
10 namespace Implab.Xml {
10 namespace Implab.Xml {
11 public static class SerializationHelpers {
11 public static class SerializationHelpers {
12 public static string SerializeAsString<T>(T obj) {
12 public static string SerializeAsString<T>(T obj) {
13 return SerializersPool<T>.Instance.SerializeAsString(obj);
13 return SerializersPool<T>.Instance.SerializeAsString(obj);
14 }
14 }
15
15
16 public static void Serialize<T>(XmlWriter writer, T obj) {
16 public static void Serialize<T>(XmlWriter writer, T obj) {
17 SerializersPool<T>.Instance.Serialize(writer, obj);
17 SerializersPool<T>.Instance.Serialize(writer, obj);
18 }
18 }
19
19
20 public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
20 public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
21 var doc = new XmlDocument();
21 var doc = new XmlDocument();
22 using (var writer = doc.CreateNavigator().AppendChild()) {
22 using (var writer = doc.CreateNavigator().AppendChild()) {
23 SerializersPool<T>.Instance.Serialize(writer, obj);
23 SerializersPool<T>.Instance.Serialize(writer, obj);
24 }
24 }
25 return doc;
25 return doc;
26 }
26 }
27
27
28 public static XDocument SerializeAsXDocument<T>(T obj) {
28 public static XDocument SerializeAsXDocument<T>(T obj) {
29 var doc = new XDocument();
29 var doc = new XDocument();
30 using (var writer = doc.CreateWriter()) {
30 using (var writer = doc.CreateWriter()) {
31 SerializersPool<T>.Instance.Serialize(writer, obj);
31 SerializersPool<T>.Instance.Serialize(writer, obj);
32 }
32 }
33 return doc;
33 return doc;
34 }
34 }
35
35
36 public static void SerializeToFile<T>(string file, T obj) {
36 public static void SerializeToFile<T>(string file, T obj) {
37 using (var writer = File.CreateText(file))
37 using (var writer = File.CreateText(file))
38 SerializersPool<T>.Instance.Serialize(writer, obj);
38 SerializersPool<T>.Instance.Serialize(writer, obj);
39 }
39 }
40
40
41 public static void SerializeToElementChild<T>(XmlElement element, T obj) {
42 using(var writer = element.CreateNavigator().AppendChild())
43 SerializersPool<T>.Instance.Serialize(writer, obj);
44 }
45
46 public static T Deserialize<T>(XmlReader reader) {
47 return SerializersPool<T>.Instance.Deserialize(reader);
48 }
49
50 public static T DeserializeFromFile<T>(string file) {
51 using(var reader = XmlReader.Create(File.OpenText(file)))
52 return Deserialize<T>(reader);
53 }
54
41 public static T DeserializeFromString<T>(string data) {
55 public static T DeserializeFromString<T>(string data) {
42 return SerializersPool<T>.Instance.DeserializeFromString(data);
56 return SerializersPool<T>.Instance.DeserializeFromString(data);
43 }
57 }
44
58
45 public static T DeserializeFromXmlNode<T>(XmlNode node) {
59 public static T DeserializeFromXmlNode<T>(XmlNode node) {
46 Safe.ArgumentNotNull(node, nameof(node));
60 Safe.ArgumentNotNull(node, nameof(node));
47 using (var reader = node.CreateNavigator().ReadSubtree())
61 using (var reader = node.CreateNavigator().ReadSubtree())
48 return SerializersPool<T>.Instance.Deserialize(reader);
62 return SerializersPool<T>.Instance.Deserialize(reader);
49 }
63 }
50 }
64 }
51 }
65 }
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