##// END OF EJS Templates
Слияние с ref20160224
cin -
r190:1c2a16d071a7 merge v2
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,195
1 using System;
2 using System.Reflection;
3 using System.Threading;
4 using Implab.Parallels;
5 using Implab.Components;
6
7 #if MONO
8
9 using NUnit.Framework;
10 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
11 using TestMethodAttribute = NUnit.Framework.TestAttribute;
12 using AssertFailedException = NUnit.Framework.AssertionException;
13 #else
14
15 using Microsoft.VisualStudio.TestTools.UnitTesting;
16
17 #endif
18
19 namespace Implab.Test {
20 [TestClass]
21 public class RunnableComponentTests {
22
23 static void ShouldThrow(Action action) {
24 try {
25 action();
26 Assert.Fail();
27 } catch (AssertFailedException) {
28 throw;
29 } catch {
30 }
31 }
32
33 class Runnable : RunnableComponent {
34 public Runnable(bool initialized) : base(initialized) {
35 }
36
37 public Action MockInit {
38 get;
39 set;
40 }
41
42 public Func<IPromise> MockStart {
43 get;
44 set;
45 }
46
47 public Func<IPromise> MockStop {
48 get;
49 set;
50 }
51
52 protected override IPromise OnStart() {
53 return MockStart != null ? MockStart() : base.OnStart();
54 }
55
56 protected override IPromise OnStop() {
57 return MockStop != null ? MockStop() : base.OnStart();
58 }
59
60 protected override void OnInitialize() {
61 if (MockInit != null)
62 MockInit();
63 }
64 }
65
66 [TestMethod]
67 public void NormalFlowTest() {
68 var comp = new Runnable(false);
69
70 Assert.AreEqual(ExecutionState.Created, comp.State);
71
72 comp.Init();
73
74 Assert.AreEqual(ExecutionState.Ready, comp.State);
75
76 comp.Start().Join(1000);
77
78 Assert.AreEqual(ExecutionState.Running, comp.State);
79
80 comp.Stop().Join(1000);
81
82 Assert.AreEqual(ExecutionState.Disposed, comp.State);
83
84 }
85
86 [TestMethod]
87 public void InitFailTest() {
88 var comp = new Runnable(false) {
89 MockInit = () => {
90 throw new Exception("BAD");
91 }
92 };
93
94 ShouldThrow(() => comp.Start());
95 ShouldThrow(() => comp.Stop());
96 Assert.AreEqual(ExecutionState.Created, comp.State);
97
98 ShouldThrow(comp.Init);
99
100 Assert.AreEqual(ExecutionState.Failed, comp.State);
101
102 ShouldThrow(() => comp.Start());
103 ShouldThrow(() => comp.Stop());
104 Assert.AreEqual(ExecutionState.Failed, comp.State);
105
106 comp.Dispose();
107 Assert.AreEqual(ExecutionState.Disposed, comp.State);
108 }
109
110 [TestMethod]
111 public void DisposedTest() {
112
113 var comp = new Runnable(false);
114 comp.Dispose();
115
116 ShouldThrow(() => comp.Start());
117 ShouldThrow(() => comp.Stop());
118 ShouldThrow(comp.Init);
119
120 Assert.AreEqual(ExecutionState.Disposed, comp.State);
121 }
122
123 [TestMethod]
124 public void StartCancelTest() {
125 var comp = new Runnable(true) {
126 MockStart = () => PromiseHelper.Sleep(100000, 0)
127 };
128
129 var p = comp.Start();
130 Assert.AreEqual(ExecutionState.Starting, comp.State);
131 p.Cancel();
132 ShouldThrow(() => p.Join(1000));
133 Assert.AreEqual(ExecutionState.Failed, comp.State);
134
135 Assert.IsInstanceOfType(comp.LastError, typeof(OperationCanceledException));
136
137 comp.Dispose();
138 }
139
140 [TestMethod]
141 public void StartStopTest() {
142 var stop = new Signal();
143 var comp = new Runnable(true) {
144 MockStart = () => PromiseHelper.Sleep(100000, 0),
145 MockStop = () => AsyncPool.RunThread(stop.Wait)
146 };
147
148 var p1 = comp.Start();
149 var p2 = comp.Stop();
150 // should enter stopping state
151
152 ShouldThrow(p1.Join);
153 Assert.IsTrue(p1.IsCancelled);
154 Assert.AreEqual(ExecutionState.Stopping, comp.State);
155
156 stop.Set();
157 p2.Join(1000);
158 Assert.AreEqual(ExecutionState.Disposed, comp.State);
159 }
160
161 [TestMethod]
162 public void StartStopFailTest() {
163 var comp = new Runnable(true) {
164 MockStart = () => PromiseHelper.Sleep(100000, 0).Then(null,null,x => { throw new Exception("I'm dead"); })
165 };
166
167 comp.Start();
168 var p = comp.Stop();
169 // if Start fails to cancel, should fail to stop
170 ShouldThrow(() => p.Join(1000));
171 Assert.AreEqual(ExecutionState.Failed, comp.State);
172 Assert.IsNotNull(comp.LastError);
173 Assert.AreEqual("I'm dead", comp.LastError.Message);
174 }
175
176 [TestMethod]
177 public void StopCancelTest() {
178 var comp = new Runnable(true) {
179 MockStop = () => PromiseHelper.Sleep(100000, 0)
180 };
181
182 comp.Start();
183 var p = comp.Stop();
184 Assert.AreEqual(ExecutionState.Stopping, comp.State);
185 p.Cancel();
186 ShouldThrow(() => p.Join(1000));
187 Assert.AreEqual(ExecutionState.Failed, comp.State);
188 Assert.IsInstanceOfType(comp.LastError, typeof(OperationCanceledException));
189
190 comp.Dispose();
191 }
192
193 }
194 }
195
@@ -0,0 +1,45
1 using System;
2 using System.Threading;
3
4 namespace Implab {
5 /// <summary>
6 /// Базовый класс для реализации задачь. Задача представляет собой некторое
7 /// действие, которое можно иницировать и обработать результат его выполнения
8 /// в виде обещания, для этого оно реализует интерфейс <see cref="IPromise"/>.
9 /// </summary>
10 /// <remarks>
11 /// Данный класс определяет стандартное поведение при обработки результатов, в частности
12 /// обработку <see cref="System.OperationCanceledException"/> и <see cref="PromiseTransientException"/>
13 /// </remarks>
14 public abstract class AbstractTask : AbstractPromise {
15 int m_cancelationLock;
16
17 /// <summary>
18 /// Получает эксклюзивное право отмены задания, используется для отмены задания до начала его выполнения.
19 /// </summary>
20 /// <returns><c>true</c>, if cancelation was locked, <c>false</c> otherwise.</returns>
21 protected bool LockCancelation() {
22 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
23 }
24
25
26
27 protected void SetErrorInternal(Exception error) {
28 // unwrap
29 while (error is PromiseTransientException && error.InnerException != null)
30 error = error.InnerException;
31
32 if (error is OperationCanceledException)
33 SetCancelled(error);
34 else
35 SetError(error);
36 }
37
38 protected void SetCancelledInternal(Exception reason) {
39 SetCancelled(
40 reason == null ? new OperationCanceledException() : reason is OperationCanceledException ? reason : new OperationCanceledException(null, reason)
41 );
42 }
43 }
44 }
45
@@ -0,0 +1,36
1 using System;
2 using System.Threading;
3
4 namespace Implab {
5 public abstract class AbstractTask<T> : AbstractPromise<T> {
6 int m_cancelationLock;
7
8 /// <summary>
9 /// Получает эксклюзивное право отмены задания, используется для отмены задания до начала его выполнения.
10 /// </summary>
11 /// <returns><c>true</c>, if cancelation was locked, <c>false</c> otherwise.</returns>
12 protected bool LockCancelation() {
13 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
14 }
15
16
17
18 protected void SetErrorInternal(Exception error) {
19 // unwrap
20 while (error is PromiseTransientException && error.InnerException != null)
21 error = error.InnerException;
22
23 if (error is OperationCanceledException)
24 SetCancelled(error);
25 else
26 SetError(error);
27 }
28
29 protected void SetCancelledInternal(Exception reason) {
30 SetCancelled(
31 reason == null ? new OperationCanceledException() : reason is OperationCanceledException ? reason : new OperationCanceledException(null, reason)
32 );
33 }
34 }
35 }
36
@@ -0,0 +1,9
1
2 namespace Implab.Automaton {
3 public static class AutomatonConst {
4 public const int UNREACHABLE_STATE = -1;
5
6 public const int UNCLASSIFIED_INPUT = 0;
7 }
8 }
9
@@ -0,0 +1,33
1 using System;
2
3 namespace Implab.Automaton {
4 public struct AutomatonTransition : IEquatable<AutomatonTransition> {
5 public readonly int s1;
6 public readonly int s2;
7 public readonly int edge;
8
9 public AutomatonTransition(int s1, int s2, int edge) {
10 this.s1 = s1;
11 this.s2 = s2;
12 this.edge = edge;
13 }
14
15
16 #region IEquatable implementation
17 public bool Equals(AutomatonTransition other) {
18 return other.s1 == s1 && other.s2 == s2 && other.edge == edge ;
19 }
20 #endregion
21
22 public override bool Equals(object obj) {
23 if (obj is AutomatonTransition)
24 return Equals((AutomatonTransition)obj);
25 return base.Equals(obj);
26 }
27
28 public override int GetHashCode() {
29 return s1 + s2 + edge;
30 }
31 }
32 }
33
@@ -0,0 +1,348
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Diagnostics;
6 using System.IO;
7 using System.CodeDom.Compiler;
8 using System.CodeDom;
9
10 namespace Implab.Automaton {
11 public class DFATable : IDFATableBuilder {
12 int m_stateCount;
13 int m_symbolCount;
14 int m_initialState;
15
16 readonly HashSet<int> m_finalStates = new HashSet<int>();
17 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
18
19
20 #region IDFADefinition implementation
21
22 public bool IsFinalState(int s) {
23 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
24
25 return m_finalStates.Contains(s);
26 }
27
28 public IEnumerable<int> FinalStates {
29 get {
30 return m_finalStates;
31 }
32 }
33
34 public int StateCount {
35 get { return m_stateCount; }
36 }
37
38 public int AlphabetSize {
39 get { return m_symbolCount; }
40 }
41
42 public int InitialState {
43 get { return m_initialState; }
44 }
45
46 #endregion
47
48 public void SetInitialState(int s) {
49 Safe.ArgumentAssert(s >= 0, "s");
50 m_stateCount = Math.Max(m_stateCount, s + 1);
51 m_initialState = s;
52 }
53
54 public void MarkFinalState(int state) {
55 m_stateCount = Math.Max(m_stateCount, state + 1);
56 m_finalStates.Add(state);
57 }
58
59 public void Add(AutomatonTransition item) {
60 Safe.ArgumentAssert(item.s1 >= 0, "item");
61 Safe.ArgumentAssert(item.s2 >= 0, "item");
62 Safe.ArgumentAssert(item.edge >= 0, "item");
63
64 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
65 m_symbolCount = Math.Max(m_symbolCount, item.edge + 1);
66
67 m_transitions.Add(item);
68 }
69
70 public void Clear() {
71 m_stateCount = 0;
72 m_symbolCount = 0;
73 m_finalStates.Clear();
74 m_transitions.Clear();
75 }
76
77 public bool Contains(AutomatonTransition item) {
78 return m_transitions.Contains(item);
79 }
80
81 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
82 m_transitions.CopyTo(array, arrayIndex);
83 }
84
85 public bool Remove(AutomatonTransition item) {
86 return m_transitions.Remove(item);
87 }
88
89 public int Count {
90 get {
91 return m_transitions.Count;
92 }
93 }
94
95 public bool IsReadOnly {
96 get {
97 return false;
98 }
99 }
100
101 public IEnumerator<AutomatonTransition> GetEnumerator() {
102 return m_transitions.GetEnumerator();
103 }
104
105 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
106 return GetEnumerator();
107 }
108
109 public void AddSymbol(int symbol) {
110 Safe.ArgumentAssert(symbol >= 0, "symbol");
111 m_symbolCount = Math.Max(symbol + 1, m_symbolCount);
112 }
113
114 public int[,] CreateTransitionTable() {
115 var table = new int[StateCount,AlphabetSize];
116
117 for (int i = 0; i < StateCount; i++)
118 for (int j = 0; j < AlphabetSize; j++)
119 table[i, j] = AutomatonConst.UNREACHABLE_STATE;
120
121 foreach (var t in this)
122 table[t.s1,t.edge] = t.s2;
123
124 return table;
125 }
126
127 public bool[] CreateFinalStateTable() {
128 var table = new bool[StateCount];
129
130 foreach (var s in FinalStates)
131 table[s] = true;
132
133 return table;
134 }
135
136 /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary>
137 /// <remarks>
138 /// В процессе построения минимального автомата требуется разделить множество состояний,
139 /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества
140 /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний,
141 /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний.
142 /// </remarks>
143 /// <returns>The final states.</returns>
144 protected virtual IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
145 return new [] { new HashSet<int>(states) };
146 }
147
148 protected void Optimize(
149 IDFATableBuilder optimalDFA,
150 IDictionary<int,int> alphabetMap,
151 IDictionary<int,int> stateMap
152 ) {
153 Safe.ArgumentNotNull(optimalDFA, "dfa");
154 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
155 Safe.ArgumentNotNull(stateMap, "stateMap");
156
157
158 var setComparer = new CustomEqualityComparer<HashSet<int>>(
159 (x, y) => x.SetEquals(y),
160 s => s.Sum(x => x.GetHashCode())
161 );
162
163 var optimalStates = new HashSet<HashSet<int>>(setComparer);
164 var queue = new HashSet<HashSet<int>>(setComparer);
165
166 optimalStates.Add(new HashSet<int>(FinalStates));
167
168 var state = new HashSet<int>(
169 Enumerable
170 .Range(0, m_stateCount)
171 .Where(i => !m_finalStates.Contains(i))
172 );
173
174 optimalStates.Add(state);
175 queue.Add(state);
176
177 var rmap = m_transitions
178 .GroupBy(t => t.s2)
179 .ToDictionary(
180 g => g.Key, // s2
181 g => g.ToLookup(t => t.edge, t => t.s1)//.ToDictionary(p => p.Key)
182 );
183
184 while (queue.Count > 0) {
185 var stateA = queue.First();
186 queue.Remove(stateA);
187
188 for (int c = 0; c < m_symbolCount; c++) {
189 var stateX = new HashSet<int>();
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'
192
193 var tmp = optimalStates.ToArray();
194 foreach (var stateY in tmp) {
195 var stateR1 = new HashSet<int>(stateY);
196 var stateR2 = new HashSet<int>(stateY);
197
198 stateR1.IntersectWith(stateX);
199 stateR2.ExceptWith(stateX);
200
201 if (stateR1.Count > 0 && stateR2.Count > 0) {
202
203
204 optimalStates.Remove(stateY);
205 optimalStates.Add(stateR1);
206 optimalStates.Add(stateR2);
207
208 if (queue.Contains(stateY)) {
209 queue.Remove(stateY);
210 queue.Add(stateR1);
211 queue.Add(stateR2);
212 } else {
213 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
214 }
215 }
216 }
217 }
218 }
219
220 // дополнительно разбиваем конечные состояния
221 foreach (var final in optimalStates.Where(s => s.Overlaps(m_finalStates)).ToArray()) {
222 optimalStates.Remove(final);
223 foreach (var split in SplitFinalStates(final))
224 optimalStates.Add(split);
225 }
226
227
228 // карта получения оптимального состояния по соотвествующему ему простому состоянию
229 var nextState = 0;
230 foreach (var item in optimalStates) {
231 var id = nextState++;
232 foreach (var s in item)
233 stateMap[s] = id;
234 }
235
236 // получаем минимальный алфавит
237 // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s
238 // для этого используем алгоритм кластеризации, сначала
239 // считаем, что все символы не различимы
240
241 var minClasses = new HashSet<HashSet<int>>(setComparer);
242 var alphaQueue = new Queue<HashSet<int>>();
243 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
244
245 // для всех состояний, будем проверять каждый класс на различимость,
246 // т.е. символы различимы, если они приводят к разным состояниям
247 for (int s = 0 ; s < optimalStates.Count; s++) {
248 var newQueue = new Queue<HashSet<int>>();
249
250 foreach (var A in alphaQueue) {
251 // классы из одного символа делить бесполезно, переводим их сразу в
252 // результирующий алфавит
253 if (A.Count == 1) {
254 minClasses.Add(A);
255 continue;
256 }
257
258 // различаем классы символов, которые переводят в различные оптимальные состояния
259 // optimalState -> alphaClass
260 var classes = new Dictionary<int, HashSet<int>>();
261
262 foreach (var term in A) {
263 // ищем все переходы класса по символу term
264 var s2 = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).DefaultIfEmpty(-1).First();
265
266 HashSet<int> a2;
267 if (!classes.TryGetValue(s2, out a2)) {
268 a2 = new HashSet<int>();
269 newQueue.Enqueue(a2);
270 classes[s2] = a2;
271 }
272 a2.Add(term);
273 }
274 }
275
276 if (newQueue.Count == 0)
277 break;
278 alphaQueue = newQueue;
279 }
280
281 // после окончания работы алгоритма в очереди останутся минимальные различимые классы
282 // входных символов
283 foreach (var A in alphaQueue)
284 minClasses.Add(A);
285
286 // построение отображения алфавитов входных символов.
287 // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь
288 // специальное значение, тогда сохраним минимальный класс,
289 // содержащий этот символ на томже месте.
290
291 var nextCls = 0;
292 foreach (var item in minClasses) {
293 if (nextCls == AutomatonConst.UNCLASSIFIED_INPUT)
294 nextCls++;
295
296 // сохраняем DFAConst.UNCLASSIFIED_INPUT
297 var cls = item.Contains(AutomatonConst.UNCLASSIFIED_INPUT) ? AutomatonConst.UNCLASSIFIED_INPUT : nextCls++;
298 optimalDFA.AddSymbol(cls);
299
300 foreach (var a in item)
301 alphabetMap[a] = cls;
302 }
303
304 // построение автомата
305 optimalDFA.SetInitialState(stateMap[m_initialState]);
306
307 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
308 optimalDFA.MarkFinalState(sf);
309
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);
312 }
313
314 protected string PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
315 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
316 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
317
318 var data = new List<string>();
319
320 data.Add("digraph dfa {");
321
322 foreach (var final in m_finalStates)
323 data.Add(String.Format("{0} [shape=box];",String.Join("", stateAlphabet.GetSymbols(final))));
324
325 foreach (var t in m_transitions)
326 data.Add(String.Format(
327 "{0} -> {2} [label={1}];",
328 String.Join("", stateAlphabet.GetSymbols(t.s1)),
329 ToLiteral(ToLiteral(String.Join("", t.edge == AutomatonConst.UNCLASSIFIED_INPUT ? new [] { "@" } : inputAlphabet.GetSymbols(t.edge).Select(x => x.ToString())))),
330 String.Join("", stateAlphabet.GetSymbols(t.s2))
331 ));
332 data.Add("}");
333 return String.Join("\n", data);
334 }
335
336 static string ToLiteral(string input)
337 {
338 using (var writer = new StringWriter())
339 {
340 using (var provider = CodeDomProvider.CreateProvider("CSharp"))
341 {
342 provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
343 return writer.ToString();
344 }
345 }
346 }
347 }
348 }
@@ -0,0 +1,66
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Globalization;
5 using System.Linq;
6 using System.Diagnostics.CodeAnalysis;
7
8 namespace Implab.Automaton {
9 /// <summary>
10 /// Алфавит символами которого являются элементы перечислений.
11 /// </summary>
12 /// <typeparam name="T">Тип перечислений</typeparam>
13 public class EnumAlphabet<T> : IndexedAlphabetBase<T> where T : struct, IConvertible {
14 [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
15 static readonly Lazy<T[]> _symbols = new Lazy<T[]>(GetSymbols);
16
17 [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
18 static readonly Lazy<EnumAlphabet<T>> _fullAlphabet = new Lazy<EnumAlphabet<T>>(CreateEnumAlphabet);
19
20 static EnumAlphabet<T> CreateEnumAlphabet() {
21 var symbols = _symbols.Value;
22
23 if (
24 symbols[symbols.Length - 1].ToInt32(CultureInfo.InvariantCulture) >= symbols.Length
25 || symbols[0].ToInt32(CultureInfo.InvariantCulture) != 0
26 )
27 throw new InvalidOperationException("The specified enumeration must be zero-based and continuously numbered");
28
29 return new EnumAlphabet<T>(symbols.Select(x => x.ToInt32(CultureInfo.InvariantCulture)).ToArray());
30 }
31
32 static T[] GetSymbols() {
33 if (!typeof(T).IsEnum)
34 throw new InvalidOperationException("Invalid generic parameter, enumeration is required");
35
36 if (Enum.GetUnderlyingType(typeof(T)) != typeof(Int32))
37 throw new InvalidOperationException("Only enums based on Int32 are supported");
38
39 return ((T[])Enum.GetValues(typeof(T)))
40 .OrderBy(x => x.ToInt32(CultureInfo.InvariantCulture))
41 .ToArray();
42 }
43
44 public static EnumAlphabet<T> FullAlphabet {
45 get {
46 return _fullAlphabet.Value;
47 }
48 }
49
50
51 public EnumAlphabet()
52 : base(_symbols.Value.Length) {
53 }
54
55 public EnumAlphabet(int[] map)
56 : base(map) {
57 Debug.Assert(map.Length == _symbols.Value.Length);
58 }
59
60
61 public override int GetSymbolIndex(T symbol) {
62 return symbol.ToInt32(CultureInfo.InvariantCulture);
63 }
64
65 }
66 }
@@ -0,0 +1,34
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Automaton {
8 /// <summary>
9 /// Алфавит. Множество символов, которые разбиты на классы, при этом классы имеют непрерывную нумерацию,
10 /// что позволяет использовать их в качестве индексов массивов.
11 /// </summary>
12 /// <remarks>
13 /// <para>Алфавит является сюрьективным отображением множества символов в множество индексов, это позволяет сократить размер таблицы переходов автомата
14 /// для входных символов, которые для него не различимы.</para>
15 /// </remarks>
16 /// <typeparam name="TSymbol">Тип символов.</typeparam>
17 public interface IAlphabet<TSymbol> {
18 /// <summary>
19 /// Количество классов символов в алфавите.
20 /// </summary>
21 int Count { get; }
22
23 /// <summary>
24 /// Преобразует входной символ в индекс символа из алфавита.
25 /// </summary>
26 /// <param name="symobl">Исходный символ</param>
27 /// <returns>Индекс в алфавите</returns>
28 int Translate(TSymbol symobl);
29
30 bool Contains(TSymbol symbol);
31
32 IEnumerable<TSymbol> GetSymbols(int cls);
33 }
34 }
@@ -0,0 +1,26
1
2 using System.Collections.Generic;
3
4 namespace Implab.Automaton {
5 public interface IAlphabetBuilder<TSymbol> : IAlphabet<TSymbol> {
6 /// <summary>
7 /// Добавляет новый символ в алфавит, если символ уже был добавлен, то
8 /// возвращается ранее сопоставленный с символом класс.
9 /// </summary>
10 /// <param name="symbol">Символ для добавления.</param>
11 /// <returns>Индекс класса, который попоставлен с символом.</returns>
12 int DefineSymbol(TSymbol symbol);
13
14 int DefineSymbol(TSymbol symbol, int cls);
15 /// <summary>
16 /// Доабвляем класс символов. Множеству указанных исходных символов
17 /// будет сопоставлен символ в алфавите.
18 /// </summary>
19 /// <param name="symbols">Множестов исходных символов</param>
20 /// <returns>Идентификатор символа алфавита.</returns>
21 int DefineClass(IEnumerable<TSymbol> symbols);
22
23 int DefineClass(IEnumerable<TSymbol> symbols, int cls);
24 }
25 }
26
@@ -0,0 +1,53
1 using System.Collections.Generic;
2
3
4 namespace Implab.Automaton {
5 /// <summary>
6 /// Полностью описывает DFA автомат, его поведение, состояние и входные символы.
7 /// </summary>
8 /// <example>
9 /// class MyAutomaton {
10 /// int m_current;
11 /// readonly DFAStateDescriptor<string>[] m_automaton;
12 /// readonly IAlphabet<MyCommands> m_commands;
13 ///
14 /// public MyAutomaton(IDFADefinition&lt;MyCommands,MyStates,string&gt; definition) {
15 /// m_current = definition.StateAlphabet.Translate(MyStates.Initial);
16 /// m_automaton = definition.GetTransitionTable();
17 /// m_commands = definition.InputAlphabet;
18 /// }
19 ///
20 /// // defined a method which will move the automaton to the next state
21 /// public void Move(MyCommands cmd) {
22 /// // use transition map to determine the next state
23 /// var next = m_automaton[m_current].transitions[m_commands.Translate(cmd)];
24 ///
25 /// // validate that we aren't in the unreachable state
26 /// if (next == DFAConst.UNREACHABLE_STATE)
27 /// throw new InvalidOperationException("The specified command is invalid");
28 ///
29 /// // if everything is ok
30 /// m_current = next;
31 /// }
32 /// }
33 /// </example>
34 public interface IDFATable : IEnumerable<AutomatonTransition> {
35 int StateCount {
36 get;
37 }
38
39 int AlphabetSize {
40 get;
41 }
42
43 int InitialState {
44 get;
45 }
46
47 bool IsFinalState(int s);
48
49 IEnumerable<int> FinalStates {
50 get;
51 }
52 }
53 }
@@ -0,0 +1,26
1 using System;
2 using System.Collections.Generic;
3
4 namespace Implab.Automaton {
5 public interface IDFATableBuilder : IDFATable, ICollection<AutomatonTransition> {
6 /// <summary>
7 /// Marks the state as final.
8 /// </summary>
9 /// <param name="state">State.</param>
10 void MarkFinalState(int state);
11
12 void SetInitialState(int s);
13
14 /// <summary>
15 /// Increases if needed the input alphabet size to hold the specified symbol.
16 /// </summary>
17 /// <remarks>
18 /// <code>
19 /// AlphabetSize = Math.Max(AlphabetSize, symbol + 1)
20 /// </code>
21 /// </remarks>
22 /// <param name="symbol">Symbol.</param>
23 void AddSymbol(int symbol);
24 }
25 }
26
@@ -0,0 +1,50
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Linq;
6
7 namespace Implab.Automaton {
8 /// <summary>
9 /// Indexed alphabet is the finite set of symbols where each symbol has a zero-based unique index.
10 /// </summary>
11 /// <remarks>
12 /// Indexed alphabets are usefull in bulting efficient translations from source alphabet
13 /// to the input alphabet of the automaton. It's assumed that the index to the symbol match
14 /// is well known and documented.
15 /// </remarks>
16 public abstract class IndexedAlphabetBase<T> : MapAlphabet<T> {
17
18 protected IndexedAlphabetBase() :base(true, null) {
19 }
20
21 public abstract int GetSymbolIndex(T symbol);
22
23 /// <summary>
24 /// Gets the translation map from the index of the symbol to it's class this is usefull for the optimized input symbols transtaion.
25 /// </summary>
26 /// <remarks>
27 /// The map is continous and start from the symbol with zero code. The last symbol
28 /// in the map is the last classified symbol in the alphabet, i.e. the map can be
29 /// shorter then the whole alphabet.
30 /// </remarks>
31 /// <returns>The translation map.</returns>
32 public int[] GetTranslationMap() {
33 var map = new Dictionary<int, int>();
34
35 int max = 0;
36 foreach (var p in Mappings) {
37 var index = GetSymbolIndex(p.Key);
38 max = Math.Max(max, index);
39 map[index] = p.Value;
40 }
41
42 var result = new int[max + 1];
43
44 for (int i = 0; i < result.Length; i++)
45 map.TryGetValue(i, out result[i]);
46
47 return result;
48 }
49 }
50 }
@@ -0,0 +1,84
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4
5 namespace Implab.Automaton {
6 public class MapAlphabet<T> : IAlphabetBuilder<T> {
7 readonly Dictionary<T,int> m_map;
8 int m_nextCls;
9 readonly bool m_supportUnclassified;
10
11 public MapAlphabet(bool supportUnclassified, IEqualityComparer<T> comparer) {
12 m_map = comparer != null ? new Dictionary<T, int>(comparer) : new Dictionary<T,int>();
13 m_supportUnclassified = supportUnclassified;
14 m_nextCls = supportUnclassified ? 1 : 0;
15 }
16
17 #region IAlphabetBuilder implementation
18
19 public int DefineSymbol(T symbol) {
20 int cls;
21 return m_map.TryGetValue(symbol, out cls) ? cls : DefineSymbol(symbol, m_nextCls);
22 }
23
24 public int DefineSymbol(T symbol, int cls) {
25 Safe.ArgumentAssert(cls >= 0, "cls");
26
27 m_nextCls = Math.Max(cls + 1, m_nextCls);
28 m_map.Add(symbol, cls);
29 return cls;
30 }
31
32 public int DefineClass(IEnumerable<T> symbols) {
33 return DefineClass(symbols, m_nextCls);
34 }
35
36 public int DefineClass(IEnumerable<T> symbols, int cls) {
37 Safe.ArgumentAssert(cls >= 0, "cls");
38 Safe.ArgumentNotNull(symbols, "symbols");
39
40 m_nextCls = Math.Max(cls + 1, m_nextCls);
41
42 foreach (var symbol in symbols)
43 m_map[symbol] = cls;
44 return cls;
45 }
46
47 #endregion
48
49 #region IAlphabet implementation
50
51 public int Translate(T symbol) {
52 int cls;
53 if (m_map.TryGetValue(symbol, out cls))
54 return cls;
55 if (!m_supportUnclassified)
56 throw new ArgumentOutOfRangeException("symbol", "The specified symbol isn't in the alphabet");
57 return AutomatonConst.UNCLASSIFIED_INPUT;
58 }
59
60 public int Count {
61 get {
62 return m_nextCls;
63 }
64 }
65
66 public bool Contains(T symbol) {
67 return m_supportUnclassified || m_map.ContainsKey(symbol);
68 }
69
70
71 public IEnumerable<T> GetSymbols(int cls) {
72 Safe.ArgumentAssert(!m_supportUnclassified || cls > 0, "cls");
73 return m_map.Where(p => p.Value == cls).Select(p => p.Key);
74 }
75 #endregion
76
77 public IEnumerable<KeyValuePair<T,int>> Mappings {
78 get {
79 return m_map;
80 }
81 }
82 }
83 }
84
@@ -0,0 +1,17
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Implab.Automaton {
7 [Serializable]
8 public class ParserException : Exception {
9 public ParserException() { }
10 public ParserException(string message) : base(message) { }
11 public ParserException(string message, Exception inner) : base(message, inner) { }
12 protected ParserException(
13 System.Runtime.Serialization.SerializationInfo info,
14 System.Runtime.Serialization.StreamingContext context)
15 : base(info, context) { }
16 }
17 }
@@ -0,0 +1,17
1 using System;
2
3 namespace Implab.Automaton.RegularExpressions {
4 public class AltToken: BinaryToken {
5 public AltToken(Token left, Token right)
6 : base(left, right) {
7 }
8
9 public override void Accept(IVisitor visitor) {
10 Safe.ArgumentNotNull(visitor, "visitor");
11 visitor.Visit(this);
12 }
13 public override string ToString() {
14 return String.Format(Right is BinaryToken ? "{0}|({1})" : "{0}|{1}", Left, Right);
15 }
16 }
17 }
@@ -0,0 +1,21
1 using Implab;
2
3 namespace Implab.Automaton.RegularExpressions {
4 public abstract class BinaryToken: Token {
5 readonly Token m_left;
6 readonly Token m_right;
7
8 public Token Left {
9 get { return m_left; }
10 }
11
12 public Token Right {
13 get { return m_right; }
14 }
15
16 protected BinaryToken(Token left, Token right) {
17 Safe.ArgumentNotNull(m_left = left, "left");
18 Safe.ArgumentNotNull(m_right = right, "right");
19 }
20 }
21 }
@@ -0,0 +1,22
1 using System;
2
3 namespace Implab.Automaton.RegularExpressions {
4 public class CatToken : BinaryToken {
5 public CatToken(Token left, Token right)
6 : base(left, right) {
7 }
8
9 public override void Accept(IVisitor visitor) {
10 Safe.ArgumentNotNull(visitor, "visitor");
11 visitor.Visit(this);
12 }
13
14 public override string ToString() {
15 return String.Format("{0}{1}", FormatToken(Left), FormatToken(Right));
16 }
17
18 static string FormatToken(Token token) {
19 return String.Format(token is AltToken ? "({0})" : "{0}", token);
20 }
21 }
22 }
@@ -0,0 +1,13
1 using Implab;
2
3 namespace Implab.Automaton.RegularExpressions {
4 public class EmptyToken: Token {
5 public override void Accept(IVisitor visitor) {
6 Safe.ArgumentNotNull(visitor, "visitor");
7 visitor.Visit(this);
8 }
9 public override string ToString() {
10 return "$";
11 }
12 }
13 }
@@ -0,0 +1,18
1 using Implab;
2
3 namespace Implab.Automaton.RegularExpressions {
4 /// <summary>
5 /// Конечный символ расширенного регулярного выражения, при построении ДКА
6 /// используется для определения конечных состояний.
7 /// </summary>
8 public class EndToken: Token {
9
10 public override void Accept(IVisitor visitor) {
11 Safe.ArgumentNotNull(visitor, "visitor");
12 visitor.Visit(this);
13 }
14 public override string ToString() {
15 return "#";
16 }
17 }
18 }
@@ -0,0 +1,23
1 namespace Implab.Automaton.RegularExpressions {
2 /// <summary>
3 /// Конечный символ расширенного регулярного выражения, при построении ДКА
4 /// используется для определения конечных состояний.
5 /// </summary>
6 public class EndToken<TTag>: EndToken {
7
8 readonly TTag m_tag;
9
10 public EndToken(TTag tag) {
11 m_tag = tag;
12 }
13
14 public EndToken()
15 : this(default(TTag)) {
16 }
17
18 public TTag Tag {
19 get { return m_tag; }
20 }
21
22 }
23 }
@@ -0,0 +1,7
1
2 namespace Implab.Automaton.RegularExpressions {
3 public interface ITaggedDFABuilder<TTag> : IDFATableBuilder {
4 void SetStateTag(int s, TTag[] tags);
5 }
6 }
7
@@ -0,0 +1,13
1 namespace Implab.Automaton.RegularExpressions {
2 /// <summary>
3 /// Интерфейс обходчика синтаксического дерева регулярного выражения
4 /// </summary>
5 public interface IVisitor {
6 void Visit(AltToken token);
7 void Visit(StarToken token);
8 void Visit(CatToken token);
9 void Visit(EmptyToken token);
10 void Visit(EndToken token);
11 void Visit(SymbolToken token);
12 }
13 }
@@ -0,0 +1,91
1 using System.Collections.Generic;
2 using System.Linq;
3
4 namespace Implab.Automaton.RegularExpressions {
5 public class RegularDFA<TInput, TTag> : DFATable, ITaggedDFABuilder<TTag> {
6
7 readonly Dictionary<int,TTag[]> m_tags = new Dictionary<int, TTag[]>();
8 readonly IAlphabet<TInput> m_alphabet;
9
10 public RegularDFA(IAlphabet<TInput> alphabet) {
11 Safe.ArgumentNotNull(alphabet, "aplhabet");
12
13 m_alphabet = alphabet;
14 }
15
16
17 public IAlphabet<TInput> InputAlphabet {
18 get {
19 return m_alphabet;
20 }
21 }
22
23 public void MarkFinalState(int s, TTag[] tags) {
24 MarkFinalState(s);
25 SetStateTag(s, tags);
26 }
27
28 public void SetStateTag(int s, TTag[] tags) {
29 Safe.ArgumentNotNull(tags, "tags");
30 m_tags[s] = tags;
31 }
32
33 public TTag[] GetStateTag(int s) {
34 TTag[] tags;
35 return m_tags.TryGetValue(s, out tags) ? tags : new TTag[0];
36 }
37
38 public TTag[][] CreateTagTable() {
39 var table = new TTag[StateCount][];
40
41 foreach (var pair in m_tags)
42 table[pair.Key] = pair.Value;
43
44 return table;
45 }
46
47 /// <summary>
48 /// Optimize the specified alphabet.
49 /// </summary>
50 /// <param name="alphabet">Пустой алфавит, который будет зполнен в процессе оптимизации.</param>
51 public RegularDFA<TInput,TTag> Optimize(IAlphabetBuilder<TInput> alphabet) {
52 Safe.ArgumentNotNull(alphabet, "alphabet");
53
54 var dfa = new RegularDFA<TInput, TTag>(alphabet);
55
56 var alphaMap = new Dictionary<int,int>();
57 var stateMap = new Dictionary<int,int>();
58
59 Optimize(dfa, alphaMap, stateMap);
60
61 // mark tags in the new DFA
62 foreach (var g in m_tags.Where(x => x.Key < StateCount).GroupBy(x => stateMap[x.Key], x => x.Value ))
63 dfa.SetStateTag(g.Key, g.SelectMany(x => x).ToArray());
64
65 // make the alphabet for the new DFA
66 // skip all unclassified symbols
67 foreach (var pair in alphaMap.Where(x => x.Value != 0))
68 alphabet.DefineClass(m_alphabet.GetSymbols(pair.Key), pair.Value);
69 return dfa;
70 }
71
72 protected override IEnumerable<HashSet<int>> SplitFinalStates(IEnumerable<int> states) {
73 var arrayComparer = new CustomEqualityComparer<TTag[]>(
74 (x,y) => x.Length == y.Length && x.All(it => y.Contains(it)),
75 x => x.Sum(it => x.GetHashCode())
76 );
77 return states.GroupBy(x => m_tags[x] ?? new TTag[0], arrayComparer).Select(g => new HashSet<int>(g));
78 }
79
80 public override string ToString() {
81 var states = new MapAlphabet<string>(false, null);
82
83 for (int i = 0; i < StateCount; i++)
84 states.DefineSymbol(string.Format("s{0}", i), i);
85
86 return string.Format("//[RegularDFA {1} x {2}]\n{0}", PrintDFA(InputAlphabet, states),StateCount, AlphabetSize);
87 }
88
89 }
90 }
91
@@ -0,0 +1,212
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Linq;
6
7 namespace Implab.Automaton.RegularExpressions {
8 /// <summary>
9 /// Используется для построения ДКА по регулярному выражению, сначала обходит
10 /// регулярное выражение и вычисляет followpos, затем используется метод
11 /// <see cref="BuildDFA(IDFADefinition)"/> для построения автомата.
12 /// </summary>
13 public class RegularExpressionVisitor : IVisitor {
14 int m_idx;
15 Token m_root;
16 HashSet<int> m_firstpos;
17 HashSet<int> m_lastpos;
18
19 readonly Dictionary<int, HashSet<int>> m_followpos = new Dictionary<int, HashSet<int>>();
20 readonly Dictionary<int, int> m_indexes = new Dictionary<int, int>();
21 readonly HashSet<int> m_ends = new HashSet<int>();
22
23 readonly IDFATableBuilder m_builder;
24 readonly IAlphabetBuilder<HashSet<int>> m_states = new MapAlphabet<HashSet<int>>(
25 false,
26 new CustomEqualityComparer<HashSet<int>>(
27 (x, y) => x.SetEquals(y),
28 x => x.Sum(n => n.GetHashCode())
29 )
30 );
31
32 public RegularExpressionVisitor(IDFATableBuilder builder) {
33 Safe.ArgumentNotNull(builder, "builder");
34
35 m_builder = builder;
36 }
37
38 HashSet<int> Followpos(int pos) {
39 HashSet<int> set;
40 return m_followpos.TryGetValue(pos, out set) ? set : m_followpos[pos] = new HashSet<int>();
41 }
42
43 bool Nullable(object n) {
44 if (n is EmptyToken || n is StarToken)
45 return true;
46 var altToken = n as AltToken;
47 if (altToken != null)
48 return Nullable(altToken.Left) || Nullable(altToken.Right);
49 var catToken = n as CatToken;
50 if (catToken != null)
51 return Nullable(catToken.Left) && Nullable(catToken.Right);
52 return false;
53 }
54
55 protected int Index {
56 get { return m_idx; }
57 }
58
59 public void Visit(AltToken token) {
60 if (m_root == null)
61 m_root = token;
62 var firtspos = new HashSet<int>();
63 var lastpos = new HashSet<int>();
64
65 token.Left.Accept(this);
66 firtspos.UnionWith(m_firstpos);
67 lastpos.UnionWith(m_lastpos);
68
69 token.Right.Accept(this);
70 firtspos.UnionWith(m_firstpos);
71 lastpos.UnionWith(m_lastpos);
72
73 m_firstpos = firtspos;
74 m_lastpos = lastpos;
75 }
76
77 public void Visit(StarToken token) {
78 if (m_root == null)
79 m_root = token;
80 token.Token.Accept(this);
81
82 foreach (var i in m_lastpos)
83 Followpos(i).UnionWith(m_firstpos);
84 }
85
86 public void Visit(CatToken token) {
87 if (m_root == null)
88 m_root = token;
89
90 var firtspos = new HashSet<int>();
91 var lastpos = new HashSet<int>();
92 token.Left.Accept(this);
93 firtspos.UnionWith(m_firstpos);
94 var leftLastpos = m_lastpos;
95
96 token.Right.Accept(this);
97 lastpos.UnionWith(m_lastpos);
98 var rightFirstpos = m_firstpos;
99
100 if (Nullable(token.Left))
101 firtspos.UnionWith(rightFirstpos);
102
103 if (Nullable(token.Right))
104 lastpos.UnionWith(leftLastpos);
105
106 m_firstpos = firtspos;
107 m_lastpos = lastpos;
108
109 foreach (var i in leftLastpos)
110 Followpos(i).UnionWith(rightFirstpos);
111
112 }
113
114 public void Visit(EmptyToken token) {
115 if (m_root == null)
116 m_root = token;
117 }
118
119 public void Visit(SymbolToken token) {
120 if (m_root == null)
121 m_root = token;
122 m_idx++;
123 m_indexes[m_idx] = token.Value;
124 m_firstpos = new HashSet<int>(new[] { m_idx });
125 m_lastpos = new HashSet<int>(new[] { m_idx });
126 }
127
128 public virtual void Visit(EndToken token) {
129 if (m_root == null)
130 m_root = token;
131 m_idx++;
132 m_indexes[m_idx] = AutomatonConst.UNCLASSIFIED_INPUT;
133 m_firstpos = new HashSet<int>(new[] { m_idx });
134 m_lastpos = new HashSet<int>(new[] { m_idx });
135 Followpos(m_idx);
136 m_ends.Add(m_idx);
137 }
138
139 public void BuildDFA() {
140 AddState(m_firstpos);
141 SetInitialState(m_firstpos);
142
143 if(IsFinal(m_firstpos))
144 MarkFinalState(m_firstpos);
145
146 var inputMax = m_indexes.Values.Max();
147 var queue = new Queue<HashSet<int>>();
148
149 queue.Enqueue(m_firstpos);
150
151 while (queue.Count > 0) {
152 var s1 = queue.Dequeue();
153
154 for (int a = 0; a <= inputMax; a++) {
155 var s2 = new HashSet<int>();
156 foreach (var p in s1) {
157 if (m_indexes[p] == a) {
158 s2.UnionWith(Followpos(p));
159 }
160 }
161 if (s2.Count > 0) {
162 if (!HasState(s2)) {
163 AddState(s2);
164 if (IsFinal(s2))
165 MarkFinalState(s2);
166
167 queue.Enqueue(s2);
168 }
169
170 DefineTransition(s1, s2, a);
171 }
172
173 }
174 }
175 }
176
177 protected bool HasState(HashSet<int> state) {
178 return m_states.Contains(state);
179 }
180
181 protected void AddState(HashSet<int> state) {
182 Debug.Assert(!HasState(state));
183
184 m_states.DefineSymbol(state);
185 }
186
187 protected int Translate(HashSet<int> state) {
188 Debug.Assert(HasState(state));
189
190 return m_states.Translate(state);
191 }
192
193 protected virtual void SetInitialState(HashSet<int> state) {
194 m_builder.SetInitialState(Translate(state));
195 }
196
197 protected virtual void MarkFinalState(HashSet<int> state) {
198 m_builder.MarkFinalState(Translate(state));
199 }
200
201 protected virtual void DefineTransition(HashSet<int> s1, HashSet<int> s2, int ch) {
202
203 m_builder.Add(new AutomatonTransition(Translate(s1), Translate(s2), ch));
204 }
205
206 bool IsFinal(IEnumerable<int> state) {
207 Debug.Assert(state != null);
208 return state.Any(m_ends.Contains);
209 }
210
211 }
212 }
@@ -0,0 +1,37
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Linq;
6
7 namespace Implab.Automaton.RegularExpressions {
8 /// <summary>
9 /// </summary>
10 public class RegularExpressionVisitor<TTag> : RegularExpressionVisitor {
11 readonly Dictionary<int, TTag> m_tags = new Dictionary<int, TTag>();
12
13 readonly ITaggedDFABuilder<TTag> m_builder;
14
15 public RegularExpressionVisitor(ITaggedDFABuilder<TTag> builder) : base(builder) {
16 m_builder = builder;
17 }
18
19 public override void Visit(EndToken token) {
20 base.Visit(token);
21 var tagged = token as EndToken<TTag>;
22 if (tagged != null)
23 m_tags.Add(Index, tagged.Tag);
24 }
25
26 protected override void MarkFinalState(HashSet<int> state) {
27 base.MarkFinalState(state);
28 m_builder.SetStateTag(Translate(state), GetStateTags(state));
29 }
30
31 TTag[] GetStateTags(IEnumerable<int> state) {
32 Debug.Assert(state != null);
33 return state.Where(m_tags.ContainsKey).Select(pos => m_tags[pos]).ToArray();
34 }
35
36 }
37 }
@@ -0,0 +1,31
1 using Implab;
2 using System;
3
4
5 namespace Implab.Automaton.RegularExpressions {
6 /// <summary>
7 /// Замыкание выражения с 0 и более повторов.
8 /// </summary>
9 public class StarToken: Token {
10
11 Token m_token;
12
13 public Token Token {
14 get { return m_token; }
15 }
16
17 public StarToken(Token token) {
18 Safe.ArgumentNotNull(token, "token");
19 m_token = token;
20 }
21
22 public override void Accept(IVisitor visitor) {
23 Safe.ArgumentNotNull(visitor, "visitor");
24 visitor.Visit(this);
25 }
26
27 public override string ToString() {
28 return String.Format("({0})*", Token);
29 }
30 }
31 }
@@ -0,0 +1,27
1 using Implab;
2
3 namespace Implab.Automaton.RegularExpressions {
4 /// <summary>
5 /// Выражение, соответсвующее одному символу.
6 /// </summary>
7 public class SymbolToken: Token {
8 int m_value;
9
10 public int Value {
11 get { return m_value; }
12 }
13
14 public SymbolToken(int value) {
15 m_value = value;
16 }
17 public override void Accept(IVisitor visitor) {
18 Safe.ArgumentNotNull(visitor, "visitor");
19
20 visitor.Visit(this);
21 }
22
23 public override string ToString() {
24 return Value.ToString();
25 }
26 }
27 }
@@ -0,0 +1,63
1 using Implab;
2 using System;
3 using System.Linq;
4
5 namespace Implab.Automaton.RegularExpressions {
6 public abstract class Token {
7 public abstract void Accept(IVisitor visitor);
8
9 public Token End() {
10 return Cat(new EndToken());
11 }
12
13 public Token Tag<TTag>(TTag tag) {
14 return Cat(new EndToken<TTag>(tag));
15 }
16
17 public Token Cat(Token right) {
18 return new CatToken(this, right);
19 }
20
21 public Token Or(Token right) {
22 return new AltToken(this, right);
23 }
24
25 public Token Optional() {
26 return Or(new EmptyToken());
27 }
28
29 public Token EClosure() {
30 return new StarToken(this);
31 }
32
33 public Token Closure() {
34 return Cat(new StarToken(this));
35 }
36
37 public Token Repeat(int count) {
38 Token token = null;
39
40 for (int i = 0; i < count; i++)
41 token = token != null ? token.Cat(this) : this;
42 return token ?? new EmptyToken();
43 }
44
45 public Token Repeat(int min, int max) {
46 if (min > max || min < 1)
47 throw new ArgumentOutOfRangeException();
48 var token = Repeat(min);
49
50 for (int i = min; i < max; i++)
51 token = token.Cat( Optional() );
52 return token;
53 }
54
55 public static Token New(params int[] set) {
56 Safe.ArgumentNotNull(set, "set");
57 Token token = null;
58 foreach(var c in set.Distinct())
59 token = token == null ? new SymbolToken(c) : token.Or(new SymbolToken(c));
60 return token;
61 }
62 }
63 }
@@ -0,0 +1,64
1 using System;
2 using System.Threading;
3
4 namespace Implab.Components {
5 /// <summary>
6 /// Creates an instace on-demand and allows it to be garbage collected.
7 /// </summary>
8 /// <remarks>
9 /// Usefull when dealing with memory-intensive objects which are frequently used.
10 /// This class is similar to <see cref="ObjectPool{T}"/> except it is a singleton.
11 /// </remarks>
12 public class LazyAndWeak<T> where T : class {
13
14 readonly Func<T> m_factory;
15 readonly object m_lock;
16 WeakReference m_reference;
17
18
19 public LazyAndWeak(Func<T> factory, bool useLock) {
20 Safe.ArgumentNotNull(factory, "factory");
21 m_factory = factory;
22 m_lock = useLock ? new object() : null;
23 }
24
25 public LazyAndWeak(Func<T> factory) : this(factory, false) {
26 }
27
28 public T Value {
29 get {
30 while (true) {
31 var weak = m_reference;
32 T value;
33 if (weak != null) {
34 value = weak.Target as T;
35 if (value != null)
36 return value;
37 }
38
39 if (m_lock == null) {
40 value = m_factory();
41
42 if (Interlocked.CompareExchange(ref m_reference, new WeakReference(value), weak) == weak)
43 return value;
44 } else {
45 lock (m_lock) {
46 // double check
47 weak = m_reference;
48 if (weak != null) {
49 value = weak.Target as T;
50 if (value != null)
51 return value;
52 }
53 // we are safe to write
54 value = m_factory();
55 m_reference = new WeakReference(value);
56 return value;
57 }
58 }
59 }
60 }
61 }
62 }
63 }
64
@@ -0,0 +1,23
1 using System.Collections.Generic;
2 using System.Linq;
3 using Implab.Automaton;
4
5 namespace Implab.Formats {
6 public class ByteAlphabet : IndexedAlphabetBase<byte> {
7
8 #region implemented abstract members of IndexedAlphabetBase
9
10 public override int GetSymbolIndex(byte symbol) {
11 return (int)symbol;
12 }
13
14 public IEnumerable<byte> InputSymbols {
15 get {
16 return Enumerable.Range(byte.MinValue, byte.MaxValue).Cast<byte>();
17 }
18 }
19
20 #endregion
21 }
22 }
23
@@ -0,0 +1,16
1 using System.Collections.Generic;
2 using System.Linq;
3 using Implab.Automaton;
4
5 namespace Implab.Formats {
6 public class CharAlphabet: IndexedAlphabetBase<char> {
7
8 public override int GetSymbolIndex(char symbol) {
9 return symbol;
10 }
11
12 public IEnumerable<char> InputSymbols {
13 get { return Enumerable.Range(char.MinValue, char.MaxValue).Cast<char>(); }
14 }
15 }
16 }
@@ -0,0 +1,99
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using Implab.Automaton;
6 using Implab.Automaton.RegularExpressions;
7
8 namespace Implab.Formats {
9 /// <summary>
10 /// Базовый абстрактный класс. Грамматика, позволяет формулировать выражения над алфавитом типа <c>char</c>.
11 /// </summary>
12 public abstract class Grammar<TSymbol> {
13
14 protected abstract IAlphabetBuilder<TSymbol> AlphabetBuilder {
15 get;
16 }
17
18 protected SymbolToken UnclassifiedToken() {
19 return new SymbolToken(AutomatonConst.UNCLASSIFIED_INPUT);
20 }
21
22 protected void DefineAlphabet(IEnumerable<TSymbol> alphabet) {
23 Safe.ArgumentNotNull(alphabet, "alphabet");
24
25 foreach (var ch in alphabet)
26 AlphabetBuilder.DefineSymbol(ch);
27 }
28
29 protected Token SymbolToken(TSymbol symbol) {
30 return Token.New(TranslateOrAdd(symbol));
31 }
32
33 protected Token SymbolToken(IEnumerable<TSymbol> symbols) {
34 Safe.ArgumentNotNull(symbols, "symbols");
35
36 return Token.New(TranslateOrAdd(symbols).ToArray());
37 }
38
39 protected Token SymbolSetToken(params TSymbol[] set) {
40 return SymbolToken(set);
41 }
42
43 int TranslateOrAdd(TSymbol ch) {
44 var t = AlphabetBuilder.Translate(ch);
45 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
46 t = AlphabetBuilder.DefineSymbol(ch);
47 return t;
48 }
49
50 IEnumerable<int> TranslateOrAdd(IEnumerable<TSymbol> symbols) {
51 return symbols.Distinct().Select(TranslateOrAdd);
52 }
53
54 int TranslateOrDie(TSymbol ch) {
55 var t = AlphabetBuilder.Translate(ch);
56 if (t == AutomatonConst.UNCLASSIFIED_INPUT)
57 throw new ApplicationException(String.Format("Symbol '{0}' is UNCLASSIFIED", ch));
58 return t;
59 }
60
61 IEnumerable<int> TranslateOrDie(IEnumerable<TSymbol> symbols) {
62 return symbols.Distinct().Select(TranslateOrDie);
63 }
64
65 protected Token SymbolTokenExcept(IEnumerable<TSymbol> symbols) {
66 Safe.ArgumentNotNull(symbols, "symbols");
67
68 return Token.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() );
69 }
70
71 protected abstract IndexedAlphabetBase<TSymbol> CreateAlphabet();
72
73 protected ScannerContext<TTag> BuildScannerContext<TTag>(Token regexp) {
74
75 var dfa = new RegularDFA<TSymbol, TTag>(AlphabetBuilder);
76
77 var visitor = new RegularExpressionVisitor<TTag>(dfa);
78 regexp.Accept(visitor);
79 visitor.BuildDFA();
80
81 if (dfa.IsFinalState(dfa.InitialState))
82 throw new ApplicationException("The specified language contains empty token");
83
84 var ab = CreateAlphabet();
85 var optimal = dfa.Optimize(ab);
86
87 return new ScannerContext<TTag>(
88 optimal.CreateTransitionTable(),
89 optimal.CreateFinalStateTable(),
90 optimal.CreateTagTable(),
91 optimal.InitialState,
92 ab.GetTranslationMap()
93 );
94 }
95
96 }
97
98
99 }
@@ -0,0 +1,11
1 namespace Implab.Formats.JSON {
2 /// <summary>
3 /// internal
4 /// </summary>
5 enum JSONElementContext {
6 None,
7 Object,
8 Array,
9 Closed
10 }
11 }
@@ -0,0 +1,28
1 namespace Implab.Formats.JSON {
2 /// <summary>
3 /// Тип элемента на котором находится парсер
4 /// </summary>
5 public enum JSONElementType {
6 None,
7 /// <summary>
8 /// Начало объекта
9 /// </summary>
10 BeginObject,
11 /// <summary>
12 /// Конец объекта
13 /// </summary>
14 EndObject,
15 /// <summary>
16 /// Начало массива
17 /// </summary>
18 BeginArray,
19 /// <summary>
20 /// Конец массива
21 /// </summary>
22 EndArray,
23 /// <summary>
24 /// Простое значение
25 /// </summary>
26 Value
27 }
28 }
@@ -0,0 +1,121
1 using System.Linq;
2 using Implab.Automaton.RegularExpressions;
3 using System;
4 using Implab.Automaton;
5 using Implab.Components;
6
7 namespace Implab.Formats.JSON {
8 class JSONGrammar : Grammar<char> {
9 public enum TokenType {
10 None,
11 BeginObject,
12 EndObject,
13 BeginArray,
14 EndArray,
15 String,
16 Number,
17 Literal,
18 NameSeparator,
19 ValueSeparator,
20 Whitespace,
21
22 StringBound,
23 EscapedChar,
24 UnescapedChar,
25 EscapedUnicode
26 }
27
28 static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar());
29
30 public static JSONGrammar Instance {
31 get { return _instance.Value; }
32 }
33
34 readonly ScannerContext<TokenType> m_jsonExpression;
35 readonly ScannerContext<TokenType> m_stringExpression;
36 readonly CharAlphabet m_defaultAlphabet = new CharAlphabet();
37
38 public JSONGrammar() {
39 DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x));
40 var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9'));
41 var digit9 = SymbolRangeToken('1', '9');
42 var zero = SymbolToken('0');
43 var digit = zero.Or(digit9);
44 var dot = SymbolToken('.');
45 var minus = SymbolToken('-');
46 var sign = SymbolSetToken('-', '+');
47 var expSign = SymbolSetToken('e', 'E');
48 var letters = SymbolRangeToken('a', 'z');
49 var integer = zero.Or(digit9.Cat(digit.EClosure()));
50 var frac = dot.Cat(digit.Closure());
51 var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure());
52 var quote = SymbolToken('"');
53 var backSlash = SymbolToken('\\');
54 var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r');
55 var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4));
56 var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure();
57 var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace);
58 var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace);
59 var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace);
60 var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace);
61 var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace);
62 var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace);
63
64 var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional());
65 var literal = letters.Closure();
66 var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x));
67
68 var jsonExpression =
69 number.Tag(TokenType.Number)
70 .Or(literal.Tag(TokenType.Literal))
71 .Or(quote.Tag(TokenType.StringBound))
72 .Or(beginObject.Tag(TokenType.BeginObject))
73 .Or(endObject.Tag(TokenType.EndObject))
74 .Or(beginArray.Tag(TokenType.BeginArray))
75 .Or(endArray.Tag(TokenType.EndArray))
76 .Or(nameSep.Tag(TokenType.NameSeparator))
77 .Or(valueSep.Tag(TokenType.ValueSeparator))
78 .Or(SymbolSetToken('\n', '\r', '\t', ' ').Closure().Tag(TokenType.Whitespace));
79
80
81 var jsonStringExpression =
82 quote.Tag(TokenType.StringBound)
83 .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar))
84 .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode))
85 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar));
86
87
88 m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression);
89 m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression);
90
91
92 }
93
94 protected override IAlphabetBuilder<char> AlphabetBuilder {
95 get {
96 return m_defaultAlphabet;
97 }
98 }
99
100 public ScannerContext<TokenType> JsonExpression {
101 get {
102 return m_jsonExpression;
103 }
104 }
105
106 public ScannerContext<TokenType> JsonStringExpression {
107 get {
108 return m_stringExpression;
109 }
110 }
111
112 Token SymbolRangeToken(char start, char stop) {
113 return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x));
114 }
115
116 protected override IndexedAlphabetBase<char> CreateAlphabet() {
117 return new CharAlphabet();
118 }
119
120 }
121 }
@@ -0,0 +1,293
1 using System;
2 using System.Diagnostics;
3 using System.IO;
4 using Implab.Automaton;
5 using Implab.Automaton.RegularExpressions;
6 using System.Linq;
7 using Implab.Components;
8 using System.Collections.Generic;
9
10 namespace Implab.Formats.JSON {
11 /// <summary>
12 /// Pull парсер JSON данных.
13 /// </summary>
14 /// <remarks>
15 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
16 /// оно означает текущий уровень вложенности объектов, однако закрывающий
17 /// элемент объекта и массива имеет уровень меньше, чем сам объект.
18 /// <code>
19 /// { // Level = 1
20 /// "name" : "Peter", // Level = 1
21 /// "address" : { // Level = 2
22 /// city : "Stern" // Level = 2
23 /// } // Level = 1
24 /// } // Level = 0
25 /// </code>
26 /// </remarks>
27 public class JSONParser : Disposable {
28
29 enum MemberContext {
30 MemberName,
31 MemberValue
32 }
33
34 #region Parser rules
35 struct ParserContext {
36 readonly int[,] m_dfa;
37 int m_state;
38
39 readonly JSONElementContext m_elementContext;
40
41 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
42 m_dfa = dfa;
43 m_state = state;
44 m_elementContext = context;
45 }
46
47 public bool Move(JsonTokenType token) {
48 var next = m_dfa[m_state, (int)token];
49 if (next == AutomatonConst.UNREACHABLE_STATE)
50 return false;
51 m_state = next;
52 return true;
53 }
54
55 public JSONElementContext ElementContext {
56 get { return m_elementContext; }
57 }
58 }
59
60 static readonly ParserContext _jsonContext;
61 static readonly ParserContext _objectContext;
62 static readonly ParserContext _arrayContext;
63
64 static JSONParser() {
65
66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
68
69 var objectExpression = memberExpression
70 .Cat(
71 MakeToken(JsonTokenType.ValueSeparator)
72 .Cat(memberExpression)
73 .EClosure()
74 )
75 .Optional()
76 .Cat(MakeToken(JsonTokenType.EndObject))
77 .End();
78
79 var arrayExpression = valueExpression
80 .Cat(
81 MakeToken(JsonTokenType.ValueSeparator)
82 .Cat(valueExpression)
83 .EClosure()
84 )
85 .Optional()
86 .Cat(MakeToken(JsonTokenType.EndArray))
87 .End();
88
89 var jsonExpression = valueExpression.End();
90
91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
94 }
95
96 static Token MakeToken(params JsonTokenType[] input) {
97 return Token.New( input.Select(t => (int)t).ToArray() );
98 }
99
100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
101
102 var dfa = new DFATable();
103 var builder = new RegularExpressionVisitor(dfa);
104 expr.Accept(builder);
105 builder.BuildDFA();
106
107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
108 }
109
110 #endregion
111
112 readonly JSONScanner m_scanner;
113 MemberContext m_memberContext;
114
115 JSONElementType m_elementType;
116 object m_elementValue;
117 string m_memberName = String.Empty;
118
119 Stack<ParserContext> m_stack = new Stack<ParserContext>();
120 ParserContext m_context = _jsonContext;
121
122 /// <summary>
123 /// Создает новый парсер на основе строки, содержащей JSON
124 /// </summary>
125 /// <param name="text"></param>
126 public JSONParser(string text) {
127 Safe.ArgumentNotEmpty(text, "text");
128 m_scanner = new JSONScanner(text);
129 }
130
131 /// <summary>
132 /// Создает новый экземпляр парсера, на основе текстового потока.
133 /// </summary>
134 /// <param name="reader">Текстовый поток.</param>
135 public JSONParser(TextReader reader) {
136 Safe.ArgumentNotNull(reader, "reader");
137 m_scanner = new JSONScanner(reader);
138 }
139
140 public int Level {
141 get { return m_stack.Count; }
142 }
143
144 /// <summary>
145 /// Тип текущего элемента на котором стоит парсер.
146 /// </summary>
147 public JSONElementType ElementType {
148 get { return m_elementType; }
149 }
150
151 /// <summary>
152 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
153 /// пустая строка.
154 /// </summary>
155 public string ElementName {
156 get { return m_memberName; }
157 }
158
159 /// <summary>
160 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
161 /// </summary>
162 public object ElementValue {
163 get { return m_elementValue; }
164 }
165
166 /// <summary>
167 /// Читает слеюудущий объект из потока
168 /// </summary>
169 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
170 public bool Read() {
171 object tokenValue;
172 JsonTokenType tokenType;
173
174 m_memberName = String.Empty;
175
176 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
177 if(!m_context.Move(tokenType))
178 UnexpectedToken(tokenValue, tokenType);
179
180 switch (tokenType) {
181 case JsonTokenType.BeginObject:
182 m_stack.Push(m_context);
183 m_context = _objectContext;
184
185 m_elementValue = null;
186 m_memberContext = MemberContext.MemberName;
187 m_elementType = JSONElementType.BeginObject;
188 return true;
189 case JsonTokenType.EndObject:
190 if (m_stack.Count == 0)
191 UnexpectedToken(tokenValue, tokenType);
192 m_context = m_stack.Pop();
193
194 m_elementValue = null;
195 m_elementType = JSONElementType.EndObject;
196 return true;
197 case JsonTokenType.BeginArray:
198 m_stack.Push(m_context);
199 m_context = _arrayContext;
200
201 m_elementValue = null;
202 m_memberContext = MemberContext.MemberValue;
203 m_elementType = JSONElementType.BeginArray;
204 return true;
205 case JsonTokenType.EndArray:
206 if (m_stack.Count == 0)
207 UnexpectedToken(tokenValue, tokenType);
208 m_context = m_stack.Pop();
209
210 m_elementValue = null;
211 m_elementType = JSONElementType.EndArray;
212 return true;
213 case JsonTokenType.String:
214 if (m_memberContext == MemberContext.MemberName) {
215 m_memberName = (string)tokenValue;
216 break;
217 }
218 m_elementType = JSONElementType.Value;
219 m_elementValue = tokenValue;
220 return true;
221 case JsonTokenType.Number:
222 m_elementType = JSONElementType.Value;
223 m_elementValue = tokenValue;
224 return true;
225 case JsonTokenType.Literal:
226 m_elementType = JSONElementType.Value;
227 m_elementValue = ParseLiteral((string)tokenValue);
228 return true;
229 case JsonTokenType.NameSeparator:
230 m_memberContext = MemberContext.MemberValue;
231 break;
232 case JsonTokenType.ValueSeparator:
233 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
234 break;
235 default:
236 UnexpectedToken(tokenValue, tokenType);
237 break;
238 }
239 }
240 if (m_context.ElementContext != JSONElementContext.None)
241 throw new ParserException("Unexpedted end of data");
242
243 EOF = true;
244
245 return false;
246 }
247
248 object ParseLiteral(string literal) {
249 switch (literal) {
250 case "null":
251 return null;
252 case "false":
253 return false;
254 case "true":
255 return true;
256 default:
257 UnexpectedToken(literal, JsonTokenType.Literal);
258 return null; // avoid compliler error
259 }
260 }
261
262 void UnexpectedToken(object value, JsonTokenType tokenType) {
263 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
264 }
265
266
267 /// <summary>
268 /// Признак конца потока
269 /// </summary>
270 public bool EOF {
271 get;
272 private set;
273 }
274
275 protected override void Dispose(bool disposing) {
276 if (disposing)
277 Safe.Dispose(m_scanner);
278 }
279
280 /// <summary>
281 /// Переходит в конец текущего объекта.
282 /// </summary>
283 public void SeekElementEnd() {
284 var level = Level - 1;
285
286 Debug.Assert(level >= 0);
287
288 while (Level != level)
289 Read();
290 }
291 }
292
293 }
@@ -0,0 +1,109
1 using System;
2 using System.Globalization;
3 using Implab.Automaton;
4 using System.Text;
5 using Implab.Components;
6 using System.IO;
7
8 namespace Implab.Formats.JSON {
9 /// <summary>
10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
11 /// </summary>
12 public class JSONScanner : Disposable {
13 readonly StringBuilder m_builder = new StringBuilder();
14
15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
17
18
19 readonly TextScanner m_scanner;
20
21 /// <summary>
22 /// Создает новый экземпляр сканнера
23 /// </summary>
24 public JSONScanner(string text) {
25 Safe.ArgumentNotEmpty(text, "text");
26
27 m_scanner = new StringScanner(text);
28 }
29
30 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
31 Safe.ArgumentNotNull(reader, "reader");
32
33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
34 }
35
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
37 }
38
39 /// <summary>
40 /// Читает следующий лексический элемент из входных данных.
41 /// </summary>
42 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
43 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
44 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
45 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
46 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
47 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
48 JSONGrammar.TokenType[] tag;
49 while (m_jsonContext.Execute(m_scanner, out tag)) {
50 switch (tag[0]) {
51 case JSONGrammar.TokenType.StringBound:
52 tokenValue = ReadString();
53 tokenType = JsonTokenType.String;
54 break;
55 case JSONGrammar.TokenType.Number:
56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
57 tokenType = JsonTokenType.Number;
58 break;
59 case JSONGrammar.TokenType.Whitespace:
60 continue;
61 default:
62 tokenType = (JsonTokenType)tag[0];
63 tokenValue = m_scanner.GetTokenValue();
64 break;
65 }
66 return true;
67 }
68 tokenValue = null;
69 tokenType = JsonTokenType.None;
70 return false;
71 }
72
73 string ReadString() {
74 int pos = 0;
75 var buf = new char[6]; // the buffer for unescaping chars
76
77 JSONGrammar.TokenType[] tag;
78 m_builder.Clear();
79
80 while (m_stringContext.Execute(m_scanner, out tag)) {
81 switch (tag[0]) {
82 case JSONGrammar.TokenType.StringBound:
83 return m_builder.ToString();
84 case JSONGrammar.TokenType.UnescapedChar:
85 m_scanner.CopyTokenTo(m_builder);
86 break;
87 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
88 m_scanner.CopyTokenTo(buf, 0);
89 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
90 pos++;
91 break;
92 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
93 m_scanner.CopyTokenTo(buf, 0);
94 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
95 break;
96 }
97
98 }
99
100 throw new ParserException("Unexpected end of data");
101 }
102
103 protected override void Dispose(bool disposing) {
104 if (disposing)
105 Safe.Dispose(m_scanner);
106 base.Dispose(disposing);
107 }
108 }
109 }
@@ -0,0 +1,319
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Globalization;
5 using System.Diagnostics;
6
7 namespace Implab.Formats.JSON {
8 public class JSONWriter {
9 struct Context {
10 public bool needComma;
11 public JSONElementContext element;
12 }
13 Stack<Context> m_contextStack = new Stack<Context>();
14 Context m_context;
15
16 const int BUFFER_SIZE = 64;
17
18 TextWriter m_writer;
19 readonly bool m_indent = true;
20 readonly int m_indentSize = 4;
21 readonly char[] m_buffer = new char[BUFFER_SIZE];
22 int m_bufferPos;
23
24 static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
25 static readonly char [] _escapeBKS,
26 _escapeFWD,
27 _escapeCR,
28 _escapeNL,
29 _escapeTAB,
30 _escapeBSLASH,
31 _escapeQ;
32
33 static JSONWriter() {
34 _escapeBKS = "\\b".ToCharArray();
35 _escapeFWD = "\\f".ToCharArray();
36 _escapeCR = "\\r".ToCharArray();
37 _escapeNL = "\\n".ToCharArray();
38 _escapeTAB = "\\t".ToCharArray();
39 _escapeBSLASH = "\\\\".ToCharArray();
40 _escapeQ = "\\\"".ToCharArray();
41 }
42
43 public JSONWriter(TextWriter writer) {
44 Safe.ArgumentNotNull(writer, "writer");
45 m_writer = writer;
46 }
47
48 public JSONWriter(TextWriter writer, bool indent) {
49 Safe.ArgumentNotNull(writer, "writer");
50
51 m_writer = writer;
52 m_indent = indent;
53 }
54
55 void WriteIndent() {
56 if (m_indent) {
57 var indent = new char[m_contextStack.Count * m_indentSize + 1];
58 indent[0] = '\n';
59 for (int i = 1; i < indent.Length; i++)
60 indent[i] = ' ';
61 m_writer.Write(new String(indent));
62 } else {
63 m_writer.Write(' ');
64 }
65 }
66
67 void WriteMemberName(string name) {
68 Safe.ArgumentNotEmpty(name, "name");
69 if (m_context.element != JSONElementContext.Object)
70 OperationNotApplicable("WriteMember");
71 if (m_context.needComma)
72 m_writer.Write(",");
73
74 WriteIndent();
75 m_context.needComma = true;
76 Write(name);
77 m_writer.Write(" : ");
78 }
79
80 public void WriteValue(string name, string value) {
81 WriteMemberName(name);
82 Write(value);
83 }
84
85 public void WriteValue(string name, bool value) {
86 WriteMemberName(name);
87 Write(value);
88 }
89
90 public void WriteValue(string name, double value) {
91 WriteMemberName(name);
92 Write(value);
93 }
94
95 public void WriteValue(string value) {
96 if (m_context.element == JSONElementContext.Array) {
97
98 if (m_context.needComma)
99 m_writer.Write(",");
100 WriteIndent();
101 m_context.needComma = true;
102
103 Write(value);
104 } else if (m_context.element == JSONElementContext.None) {
105 Write(value);
106 m_context.element = JSONElementContext.Closed;
107 } else {
108 OperationNotApplicable("WriteValue");
109 }
110 }
111
112 public void WriteValue(bool value) {
113 if (m_context.element == JSONElementContext.Array) {
114
115 if (m_context.needComma)
116 m_writer.Write(",");
117 WriteIndent();
118 m_context.needComma = true;
119
120 Write(value);
121 } else if (m_context.element == JSONElementContext.None) {
122 Write(value);
123 m_context.element = JSONElementContext.Closed;
124 } else {
125 OperationNotApplicable("WriteValue");
126 }
127 }
128
129 public void WriteValue(double value) {
130 if (m_context.element == JSONElementContext.Array) {
131
132 if (m_context.needComma)
133 m_writer.Write(",");
134 WriteIndent();
135 m_context.needComma = true;
136
137 Write(value);
138 } else if (m_context.element == JSONElementContext.None) {
139 Write(value);
140 m_context.element = JSONElementContext.Closed;
141 } else {
142 OperationNotApplicable("WriteValue");
143 }
144 }
145
146 public void BeginObject() {
147 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
148 OperationNotApplicable("BeginObject");
149 if (m_context.needComma)
150 m_writer.Write(",");
151
152 WriteIndent();
153
154 m_context.needComma = true;
155
156 m_contextStack.Push(m_context);
157
158 m_context = new Context { element = JSONElementContext.Object, needComma = false };
159 m_writer.Write("{");
160 }
161
162 public void BeginObject(string name) {
163 WriteMemberName(name);
164
165 m_contextStack.Push(m_context);
166
167 m_context = new Context { element = JSONElementContext.Object, needComma = false };
168 m_writer.Write("{");
169 }
170
171 public void EndObject() {
172 if (m_context.element != JSONElementContext.Object)
173 OperationNotApplicable("EndObject");
174
175 m_context = m_contextStack.Pop();
176 if (m_contextStack.Count == 0)
177 m_context.element = JSONElementContext.Closed;
178 WriteIndent();
179 m_writer.Write("}");
180 }
181
182 public void BeginArray() {
183 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
184 throw new InvalidOperationException();
185 if (m_context.needComma) {
186 m_writer.Write(",");
187
188 }
189 m_context.needComma = true;
190
191 WriteIndent();
192 m_contextStack.Push(m_context);
193 m_context = new Context { element = JSONElementContext.Array, needComma = false };
194 m_writer.Write("[");
195 }
196
197 public void BeginArray(string name) {
198 WriteMemberName(name);
199
200 m_contextStack.Push(m_context);
201
202 m_context = new Context { element = JSONElementContext.Array, needComma = false };
203 m_writer.Write("[");
204 }
205
206 public void EndArray() {
207 if (m_context.element != JSONElementContext.Array)
208 OperationNotApplicable("EndArray");
209
210 m_context = m_contextStack.Pop();
211 if (m_contextStack.Count == 0)
212 m_context.element = JSONElementContext.Closed;
213 WriteIndent();
214 m_writer.Write("]");
215 }
216
217 void Write(bool value) {
218 m_writer.Write(value ? "true" : "false");
219 }
220
221 void FlushBuffer() {
222 if (m_bufferPos > 0) {
223 m_writer.Write(m_buffer, 0, m_bufferPos);
224 m_bufferPos = 0;
225 }
226 }
227
228 void Write(string value) {
229 if (value == null) {
230 m_writer.Write("null");
231 return;
232 }
233
234 Debug.Assert(m_bufferPos == 0);
235
236 var chars = value.ToCharArray();
237 m_buffer[m_bufferPos++] = '"';
238
239 // Analysis disable once ForCanBeConvertedToForeach
240 for (int i = 0; i < chars.Length; i++) {
241 var ch = chars[i];
242
243 char[] escapeSeq;
244
245 switch (ch) {
246 case '\b':
247 escapeSeq = _escapeBKS;
248 break;
249 case '\f':
250 escapeSeq = _escapeFWD;
251 break;
252 case '\r':
253 escapeSeq = _escapeCR;
254 break;
255 case '\n':
256 escapeSeq = _escapeNL;
257 break;
258 case '\t':
259 escapeSeq = _escapeTAB;
260 break;
261 case '\\':
262 escapeSeq = _escapeBSLASH;
263 break;
264 case '"':
265 escapeSeq = _escapeQ;
266 break;
267 default:
268 if (ch < 0x20) {
269 if (m_bufferPos + 6 > BUFFER_SIZE)
270 FlushBuffer();
271
272 m_buffer[m_bufferPos++] = '\\';
273 m_buffer[m_bufferPos++] = 'u';
274 m_buffer[m_bufferPos++] = '0';
275 m_buffer[m_bufferPos++] = '0';
276 m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf];
277 m_buffer[m_bufferPos++] = _hex[ch & 0xf];
278
279 } else {
280 if (m_bufferPos >= BUFFER_SIZE)
281 FlushBuffer();
282 m_buffer[m_bufferPos++] = ch;
283 }
284 continue;
285 }
286
287 if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
288 FlushBuffer();
289
290 Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length);
291 m_bufferPos += escapeSeq.Length;
292
293 }
294
295 if (m_bufferPos >= BUFFER_SIZE)
296 FlushBuffer();
297
298 m_buffer[m_bufferPos++] = '"';
299
300 FlushBuffer();
301 }
302
303 void Write(double value) {
304 if (double.IsNaN(value))
305 Write("NaN");
306 else if (double.IsNegativeInfinity(value))
307 Write("-Infinity");
308 else if (double.IsPositiveInfinity(value))
309 Write("Infinity");
310 else
311 m_writer.Write(value.ToString(CultureInfo.InvariantCulture));
312 }
313
314 void OperationNotApplicable(string opName) {
315 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
316 }
317
318 }
319 }
@@ -0,0 +1,335
1 using Implab;
2 using System;
3 using System.Collections.Generic;
4 using System.Globalization;
5 using System.IO;
6 using System.Xml;
7
8 namespace Implab.Formats.JSON {
9 public class JSONXmlReader : XmlReader {
10
11 enum ValueContext {
12 Undefined,
13 ElementStart,
14 ElementValue,
15 ElementEnd,
16 ElementEmpty
17 }
18
19 struct LocalNameContext {
20 public string localName;
21 public bool isArray;
22 }
23
24 JSONParser m_parser;
25 ValueContext m_valueContext;
26 ReadState m_state = ReadState.Initial;
27 Stack<LocalNameContext> m_localNameStack = new Stack<LocalNameContext>();
28 LocalNameContext m_localName;
29 int m_depthCorrection;
30
31 readonly string m_rootName;
32 readonly string m_prefix;
33 readonly string m_namespaceUri;
34 readonly bool m_flattenArrays;
35 readonly string m_arrayItemName;
36 readonly XmlNameTable m_nameTable;
37
38 JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) {
39 m_parser = parser;
40
41 if (options != null) {
42 m_prefix = options.NodesPrefix ?? String.Empty;
43 m_namespaceUri = options.NamespaceURI ?? String.Empty;
44 m_rootName = options.RootName ?? "json";
45 m_flattenArrays = options.FlattenArrays;
46 m_arrayItemName = options.ArrayItemName ?? "item";
47 m_nameTable = options.NameTable ?? new NameTable();
48 } else {
49 m_prefix = String.Empty;
50 m_namespaceUri = String.Empty;
51 m_rootName = "json";
52 m_flattenArrays = false;
53 m_arrayItemName = "item";
54 m_nameTable = new NameTable();
55 }
56 }
57
58 /// <summary>
59 /// Always 0, JSON doesn't support attributes
60 /// </summary>
61 public override int AttributeCount {
62 get { return 0; }
63 }
64
65 public override string BaseURI {
66 get { return String.Empty; }
67 }
68
69 public override int Depth {
70 get {
71 return m_localNameStack.Count + m_depthCorrection;
72 }
73 }
74
75 public override bool EOF {
76 get { return m_parser.EOF; }
77 }
78
79 /// <summary>
80 /// Always throws an exception
81 /// </summary>
82 /// <param name="i"></param>
83 /// <returns></returns>
84 public override string GetAttribute(int i) {
85 throw new ArgumentOutOfRangeException();
86 }
87
88 /// <summary>
89 /// Always returns empty string
90 /// </summary>
91 /// <param name="name"></param>
92 /// <param name="namespaceURI"></param>
93 /// <returns></returns>
94 public override string GetAttribute(string name, string namespaceURI) {
95 return String.Empty;
96 }
97
98 /// <summary>
99 /// Always returns empty string
100 /// </summary>
101 /// <param name="name"></param>
102 /// <returns></returns>
103 public override string GetAttribute(string name) {
104 return String.Empty;
105 }
106
107 public override bool IsEmptyElement {
108 get { return m_parser.ElementType == JSONElementType.Value && m_valueContext == ValueContext.ElementEmpty; }
109 }
110
111 public override string LocalName {
112 get { return m_localName.localName; }
113 }
114
115 public override string LookupNamespace(string prefix) {
116 if (String.IsNullOrEmpty(prefix) || prefix == m_prefix)
117 return m_namespaceUri;
118
119 return String.Empty;
120 }
121
122 public override bool MoveToAttribute(string name, string ns) {
123 return false;
124 }
125
126 public override bool MoveToAttribute(string name) {
127 return false;
128 }
129
130 public override bool MoveToElement() {
131 return false;
132 }
133
134 public override bool MoveToFirstAttribute() {
135 return false;
136 }
137
138 public override bool MoveToNextAttribute() {
139 return false;
140 }
141
142 public override XmlNameTable NameTable {
143 get { return m_nameTable; }
144 }
145
146 public override string NamespaceURI {
147 get { return m_namespaceUri; }
148 }
149
150 public override XmlNodeType NodeType {
151 get {
152 switch (m_parser.ElementType) {
153 case JSONElementType.BeginObject:
154 case JSONElementType.BeginArray:
155 return XmlNodeType.Element;
156 case JSONElementType.EndObject:
157 case JSONElementType.EndArray:
158 return XmlNodeType.EndElement;
159 case JSONElementType.Value:
160 switch (m_valueContext) {
161 case ValueContext.ElementStart:
162 case ValueContext.ElementEmpty:
163 return XmlNodeType.Element;
164 case ValueContext.ElementValue:
165 return XmlNodeType.Text;
166 case ValueContext.ElementEnd:
167 return XmlNodeType.EndElement;
168 default:
169 throw new InvalidOperationException();
170 }
171 default:
172 throw new InvalidOperationException();
173 }
174 }
175 }
176
177 public override string Prefix {
178 get { return m_prefix; }
179 }
180
181 public override bool Read() {
182 if (m_state != ReadState.Interactive && m_state != ReadState.Initial)
183 return false;
184
185 if (m_state == ReadState.Initial)
186 m_state = ReadState.Interactive;
187
188 try {
189 switch (m_parser.ElementType) {
190 case JSONElementType.Value:
191 switch (m_valueContext) {
192 case ValueContext.ElementStart:
193 SetLocalName(String.Empty);
194 m_valueContext = ValueContext.ElementValue;
195 return true;
196 case ValueContext.ElementValue:
197 RestoreLocalName();
198 m_valueContext = ValueContext.ElementEnd;
199 return true;
200 case ValueContext.ElementEmpty:
201 case ValueContext.ElementEnd:
202 RestoreLocalName();
203 break;
204 }
205 break;
206 case JSONElementType.EndArray:
207 case JSONElementType.EndObject:
208 RestoreLocalName();
209 break;
210 }
211 string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName;
212 while (m_parser.Read()) {
213 if (!String.IsNullOrEmpty(m_parser.ElementName))
214 itemName = m_parser.ElementName;
215
216 switch (m_parser.ElementType) {
217 case JSONElementType.BeginArray:
218 if (m_flattenArrays && !m_localName.isArray) {
219 m_depthCorrection--;
220 SetLocalName(itemName, true);
221 continue;
222 }
223 SetLocalName(itemName, true);
224 break;
225 case JSONElementType.BeginObject:
226 SetLocalName(itemName);
227 break;
228 case JSONElementType.EndArray:
229 if (m_flattenArrays && !m_localNameStack.Peek().isArray) {
230 RestoreLocalName();
231 m_depthCorrection++;
232 continue;
233 }
234 break;
235 case JSONElementType.EndObject:
236 break;
237 case JSONElementType.Value:
238 SetLocalName(itemName);
239 m_valueContext = m_parser.ElementValue == null ? ValueContext.ElementEmpty : ValueContext.ElementStart;
240 break;
241 }
242 return true;
243 }
244
245 m_state = ReadState.EndOfFile;
246 return false;
247 } catch {
248 m_state = ReadState.Error;
249 throw;
250 }
251 }
252
253 public override bool ReadAttributeValue() {
254 return false;
255 }
256
257 public override ReadState ReadState {
258 get { return m_state; }
259 }
260
261 public override void ResolveEntity() {
262 // do nothing
263 }
264
265 public override string Value {
266 get {
267 if (m_parser.ElementValue == null)
268 return String.Empty;
269 if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double)
270 return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture);
271 return m_parser.ElementValue.ToString();
272 }
273 }
274
275 void SetLocalName(string name) {
276 m_localNameStack.Push(m_localName);
277 m_localName.localName = name;
278 m_localName.isArray = false;
279 }
280
281 void SetLocalName(string name, bool isArray) {
282 m_localNameStack.Push(m_localName);
283 m_localName.localName = name;
284 m_localName.isArray = isArray;
285 }
286
287 void RestoreLocalName() {
288 m_localName = m_localNameStack.Pop();
289 }
290
291 public override void Close() {
292
293 }
294
295 protected override void Dispose(bool disposing) {
296 #if MONO
297 disposing = true;
298 #endif
299 if (disposing) {
300 m_parser.Dispose();
301 }
302 base.Dispose(disposing);
303 }
304
305 public static JSONXmlReader Create(string file, JSONXmlReaderOptions options) {
306 return Create(File.OpenText(file), options);
307 }
308
309 /// <summary>
310 /// Creates the XmlReader for the specified text stream with JSON data.
311 /// </summary>
312 /// <param name="reader">Text reader.</param>
313 /// <param name="options">Options.</param>
314 /// <remarks>
315 /// The reader will be disposed when the XmlReader is disposed.
316 /// </remarks>
317 public static JSONXmlReader Create(TextReader reader, JSONXmlReaderOptions options) {
318 return new JSONXmlReader(new JSONParser(reader), options);
319 }
320
321 /// <summary>
322 /// Creates the XmlReader for the specified stream with JSON data.
323 /// </summary>
324 /// <param name="stream">Stream.</param>
325 /// <param name="options">Options.</param>
326 /// <remarks>
327 /// The stream will be disposed when the XmlReader is disposed.
328 /// </remarks>
329 public static JSONXmlReader Create(Stream stream, JSONXmlReaderOptions options) {
330 Safe.ArgumentNotNull(stream, "stream");
331 // HACK don't dispose StreaReader to keep stream opened
332 return Create(new StreamReader(stream), options);
333 }
334 }
335 }
@@ -0,0 +1,62
1
2 using System.Xml;
3
4 namespace Implab.Formats.JSON {
5 /// <summary>
6 /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
7 /// интерпретации <c>JSON</c> документа.
8 /// </summary>
9 public class JSONXmlReaderOptions {
10 /// <summary>
11 /// Пространство имен в котором будут располагаться читаемые элементы документа
12 /// </summary>
13 public string NamespaceURI {
14 get;
15 set;
16 }
17
18 /// <summary>
19 /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности), иначе массив
20 /// представляется в виде узла, дочерними элементами которого являются элементы массива, имена дочерних элементов
21 /// определяются свойством <see cref="ArrayItemName"/>. По умолчанию <c>false</c>.
22 /// </summary>
23 public bool FlattenArrays {
24 get;
25 set;
26 }
27
28 /// <summary>
29 /// Префикс, для узлов документа
30 /// </summary>
31 public string NodesPrefix {
32 get;
33 set;
34 }
35
36 /// <summary>
37 /// Имя корневого элемента в xml документе
38 /// </summary>
39 public string RootName {
40 get;
41 set;
42 }
43
44 /// <summary>
45 /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
46 /// По умолчанию <c>item</c>.
47 /// </summary>
48 public string ArrayItemName {
49 get;
50 set;
51 }
52
53 /// <summary>
54 /// Таблица атомизированных строк для построения документа.
55 /// </summary>
56 public XmlNameTable NameTable {
57 get;
58 set;
59 }
60
61 }
62 }
@@ -0,0 +1,44
1 namespace Implab.Formats.JSON {
2 /// <summary>
3 /// Тип токенов, возвращаемых <see cref="JSONScanner"/>.
4 /// </summary>
5 public enum JsonTokenType : int {
6 None = 0,
7 /// <summary>
8 /// Начало объекта
9 /// </summary>
10 BeginObject,
11 /// <summary>
12 /// Конец объекта
13 /// </summary>
14 EndObject,
15 /// <summary>
16 /// Начало массива
17 /// </summary>
18 BeginArray,
19 /// <summary>
20 /// Конец массива
21 /// </summary>
22 EndArray,
23 /// <summary>
24 /// Строка
25 /// </summary>
26 String,
27 /// <summary>
28 /// Число
29 /// </summary>
30 Number,
31 /// <summary>
32 /// Литерал
33 /// </summary>
34 Literal,
35 /// <summary>
36 /// Разделитель имени <c>:</c>
37 /// </summary>
38 NameSeparator,
39 /// <summary>
40 /// Разделитель имени <c>,</c>
41 /// </summary>
42 ValueSeparator
43 }
44 }
@@ -0,0 +1,52
1 using Implab;
2 using Implab.Formats;
3 using System;
4 using System.Collections.Generic;
5 using System.Diagnostics;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9
10 namespace Implab.Formats.JSON {
11 /// <summary>
12 /// Класс для преобразования экранированной строки JSON
13 /// </summary>
14 static class StringTranslator {
15 static readonly char[] _escMap;
16 static readonly int[] _hexMap;
17
18 static StringTranslator() {
19 var chars = new char[] { 'b', 'f', 't', 'r', 'n', '\\', '/' };
20 var vals = new char[] { '\b', '\f', '\t', '\r', '\n', '\\', '/' };
21
22 _escMap = new char[chars.Max() + 1];
23
24 for (int i = 0; i < chars.Length; i++)
25 _escMap[chars[i]] = vals[i];
26
27 var hexs = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
28 var ints = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15 };
29
30 _hexMap = new int[hexs.Max() + 1];
31
32 for (int i = 0; i < hexs.Length; i++)
33 _hexMap[hexs[i]] = ints[i];
34
35 }
36
37 internal static char TranslateEscapedChar(char symbol) {
38 return _escMap[symbol];
39 }
40
41 internal static char TranslateHexUnicode(char[] symbols, int offset) {
42 Debug.Assert(symbols != null);
43 Debug.Assert(symbols.Length - offset >= 4);
44
45 int value = (_hexMap[symbols[offset]] << 12)
46 | (_hexMap[symbols[offset + 1]] << 8)
47 | (_hexMap[symbols[offset + 2]] << 4)
48 | (_hexMap[symbols[offset + 3]]);
49 return (char)value;
50 }
51 }
52 }
@@ -0,0 +1,30
1 using System;
2 using System.IO;
3
4 namespace Implab.Formats {
5 public class ReaderScanner: TextScanner {
6 const int CHUNK_SIZE = 1024*4;
7 const int BUFFER_MAX = CHUNK_SIZE*1024;
8
9 readonly TextReader m_reader;
10
11 public ReaderScanner(TextReader reader, int limit, int chunk) : base(limit, chunk) {
12 Safe.ArgumentNotNull(reader, "reader");
13 m_reader = reader;
14 }
15
16 public ReaderScanner(TextReader reader) : this(reader, BUFFER_MAX, CHUNK_SIZE) {
17 }
18
19 protected override int Read(char[] buffer, int offset, int size) {
20 return m_reader.Read(buffer, offset, size);
21 }
22
23 protected override void Dispose(bool disposing) {
24 if (disposing)
25 Safe.Dispose(m_reader);
26 base.Dispose(disposing);
27 }
28 }
29 }
30
@@ -0,0 +1,30
1 namespace Implab.Formats {
2 /// <summary>
3 /// Represents a scanner configuration usefull to recongnize token, based on the DFA.
4 /// </summary>
5 public class ScannerContext<TTag> {
6
7 public int[,] Dfa { get; private set; }
8
9 public bool[] Final { get; private set; }
10
11 public TTag[][] Tags { get; private set; }
12
13 public int State { get; private set; }
14
15 public int[] Alphabet { get; private set; }
16
17 public ScannerContext(int[,] dfa, bool[] final, TTag[][] tags, int state, int[] alphabet) {
18 Dfa = dfa;
19 Final = final;
20 Tags = tags;
21 State = state;
22 Alphabet = alphabet;
23 }
24
25 public bool Execute(TextScanner scanner, out TTag[] tag) {
26 return scanner.ReadToken(Dfa, Final, Tags, State, Alphabet, out tag);
27 }
28 }
29 }
30
@@ -0,0 +1,18
1 using System;
2
3 namespace Implab.Formats {
4 public class StringScanner: TextScanner {
5 const int CHUNK_SIZE = 1024;
6
7 public StringScanner(string text) : base(null) {
8 Safe.ArgumentNotNull(text, "text");
9 var data = text.ToCharArray();
10 Feed(data, 0, data.Length);
11 }
12
13 protected override int Read(char[] buffer, int offset, int size) {
14 return 0;
15 }
16 }
17 }
18
@@ -0,0 +1,157
1 using System;
2 using Implab.Components;
3 using System.Diagnostics;
4 using Implab.Automaton;
5 using System.Text;
6
7 namespace Implab.Formats {
8 public abstract class TextScanner : Disposable {
9 readonly int m_bufferMax;
10 readonly int m_chunkSize;
11
12 char[] m_buffer;
13 int m_bufferOffset;
14 int m_bufferSize;
15 int m_tokenOffset;
16 int m_tokenLength;
17
18 /// <summary>
19 /// Initializes a new instance of the <see cref="Implab.Formats.TextScanner"/> class.
20 /// </summary>
21 /// <param name="bufferMax">Buffer max.</param>
22 /// <param name="chunkSize">Chunk size.</param>
23 protected TextScanner(int bufferMax, int chunkSize) {
24 Debug.Assert(m_chunkSize <= m_bufferMax);
25
26 m_bufferMax = bufferMax;
27 m_chunkSize = chunkSize;
28 }
29
30 /// <summary>
31 /// Initializes a new instance of the <see cref="Implab.Formats.TextScanner"/> class.
32 /// </summary>
33 /// <param name="buffer">Buffer.</param>
34 protected TextScanner(char[] buffer) {
35 if (buffer != null) {
36 m_buffer = buffer;
37 m_bufferSize = buffer.Length;
38 }
39 }
40
41 /// <summary>
42 /// (hungry) Reads the next token.
43 /// </summary>
44 /// <returns><c>true</c>, if token internal was read, <c>false</c> if there is no more tokens in the stream.</returns>
45 /// <param name="dfa">The transition map for the automaton</param>
46 /// <param name="final">Final states of the automaton.</param>
47 /// <param name="tags">Tags.</param>
48 /// <param name="state">The initial state for the automaton.</param>
49 /// <param name="alphabet"></param>
50 /// <param name = "tag"></param>
51 internal bool ReadToken<TTag>(int[,] dfa, bool[] final, TTag[][] tags, int state, int[] alphabet, out TTag[] tag) {
52 m_tokenLength = 0;
53 tag = null;
54
55 var maxSymbol = alphabet.Length - 1;
56 int next;
57 do {
58 // after the next chunk is read the offset in the buffer may change
59 int pos = m_bufferOffset + m_tokenLength;
60 next = state;
61 while (pos < m_bufferSize) {
62 var ch = m_buffer[pos];
63
64 next = dfa[next, ch > maxSymbol ? AutomatonConst.UNCLASSIFIED_INPUT : alphabet[ch]];
65
66 if (next == AutomatonConst.UNREACHABLE_STATE)
67 break;
68
69 state = next;
70 pos++;
71 }
72 m_tokenLength = pos - m_bufferOffset;
73 } while (next != AutomatonConst.UNREACHABLE_STATE && Feed());
74
75 m_tokenOffset = m_bufferOffset;
76 m_bufferOffset += m_tokenLength;
77
78 if (final[state]) {
79 tag = tags[state];
80 return true;
81 }
82
83 if (m_bufferOffset == m_bufferSize) {
84 if (m_tokenLength == 0) //EOF
85 return false;
86
87 throw new ParserException();
88 }
89
90 throw new ParserException(String.Format("Unexpected symbol '{0}'", m_buffer[m_bufferOffset]));
91
92 }
93
94 protected void Feed(char[] buffer, int offset, int length) {
95 m_buffer = buffer;
96 m_bufferOffset = offset;
97 m_bufferSize = offset + length;
98 }
99
100 protected bool Feed() {
101 if (m_chunkSize <= 0)
102 return false;
103
104 if (m_buffer != null) {
105 var free = m_buffer.Length - m_bufferSize;
106
107 if (free < m_chunkSize) {
108 free += m_chunkSize;
109 var used = m_bufferSize - m_bufferOffset;
110 var size = used + free;
111
112 if (size > m_bufferMax)
113 throw new ParserException(String.Format("The buffer limit ({0} Kb) is reached", m_bufferMax / 1024));
114
115 var temp = new char[size];
116
117 var read = Read(temp, used, m_chunkSize);
118 if (read == 0)
119 return false;
120
121 Array.Copy(m_buffer, m_bufferOffset, temp, 0, used);
122
123 m_bufferOffset = 0;
124 m_bufferSize = used + read;
125 m_buffer = temp;
126 } else {
127 var read = Read(m_buffer, m_bufferSize, m_chunkSize);
128 if (read == 0)
129 return false;
130 m_bufferSize += m_chunkSize;
131 }
132 return true;
133 } else {
134 Debug.Assert(m_bufferOffset == 0);
135 m_buffer = new char[m_chunkSize];
136 m_bufferSize = Read(m_buffer, 0, m_chunkSize);
137 return (m_bufferSize != 0);
138 }
139 }
140
141 protected abstract int Read(char[] buffer, int offset, int size);
142
143 public string GetTokenValue() {
144 return new String(m_buffer, m_tokenOffset, m_tokenLength);
145 }
146
147 public void CopyTokenTo(char[] buffer, int offset) {
148 Array.Copy(m_buffer, m_tokenOffset,buffer, offset, m_tokenLength);
149 }
150
151 public void CopyTokenTo(StringBuilder sb) {
152 sb.Append(m_buffer, m_tokenOffset, m_tokenLength);
153 }
154
155 }
156 }
157
@@ -0,0 +1,4
1 <?xml version="1.0" encoding="utf-8"?>
2 <packages>
3 <package id="System.Text.Json" version="2.0.0.11" targetFramework="net45" />
4 </packages> No newline at end of file
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -1,17 +1,20
1 syntax: glob
1 syntax: glob
2 Implab.Test/bin/
2 Implab.Test/bin/
3 *.user
3 *.user
4 Implab.Test/obj/
4 Implab.Test/obj/
5 *.userprefs
5 *.userprefs
6 Implab/bin/
6 Implab/bin/
7 Implab/obj/
7 Implab/obj/
8 TestResults/
8 TestResults/
9 Implab.Fx/obj/
9 Implab.Fx/obj/
10 Implab.Fx/bin/
10 Implab.Fx/bin/
11 Implab.Fx.Test/bin/
11 Implab.Fx.Test/bin/
12 Implab.Fx.Test/obj/
12 Implab.Fx.Test/obj/
13 _ReSharper.Implab/
13 _ReSharper.Implab/
14 Implab.Diagnostics.Interactive/bin/
14 Implab.Diagnostics.Interactive/bin/
15 Implab.Diagnostics.Interactive/obj/
15 Implab.Diagnostics.Interactive/obj/
16 MonoPlay/bin/
16 MonoPlay/bin/
17 MonoPlay/obj/
17 MonoPlay/obj/
18 Implab.Test/Implab.Format.Test/bin/
19 Implab.Test/Implab.Format.Test/obj/
20 *.suo
@@ -1,45 +1,52
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{4D364996-7ECD-4193-8F90-F223FFEA49DA}</ProjectGuid>
8 <ProjectGuid>{4D364996-7ECD-4193-8F90-F223FFEA49DA}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <RootNamespace>Implab.Format.Test</RootNamespace>
10 <RootNamespace>Implab.Format.Test</RootNamespace>
11 <AssemblyName>Implab.Format.Test</AssemblyName>
11 <AssemblyName>Implab.Format.Test</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <ReleaseVersion>0.2</ReleaseVersion>
13 </PropertyGroup>
14 </PropertyGroup>
14 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <DebugSymbols>true</DebugSymbols>
16 <DebugSymbols>true</DebugSymbols>
16 <DebugType>full</DebugType>
17 <DebugType>full</DebugType>
17 <Optimize>false</Optimize>
18 <Optimize>false</Optimize>
18 <OutputPath>bin\Debug</OutputPath>
19 <OutputPath>bin\Debug</OutputPath>
19 <DefineConstants>DEBUG;</DefineConstants>
20 <DefineConstants>DEBUG;</DefineConstants>
20 <ErrorReport>prompt</ErrorReport>
21 <ErrorReport>prompt</ErrorReport>
21 <WarningLevel>4</WarningLevel>
22 <WarningLevel>4</WarningLevel>
22 <ConsolePause>false</ConsolePause>
23 <ConsolePause>false</ConsolePause>
23 </PropertyGroup>
24 </PropertyGroup>
24 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <DebugType>full</DebugType>
26 <DebugType>full</DebugType>
26 <Optimize>true</Optimize>
27 <Optimize>true</Optimize>
27 <OutputPath>bin\Release</OutputPath>
28 <OutputPath>bin\Release</OutputPath>
28 <ErrorReport>prompt</ErrorReport>
29 <ErrorReport>prompt</ErrorReport>
29 <WarningLevel>4</WarningLevel>
30 <WarningLevel>4</WarningLevel>
30 <ConsolePause>false</ConsolePause>
31 <ConsolePause>false</ConsolePause>
31 </PropertyGroup>
32 </PropertyGroup>
32 <ItemGroup>
33 <ItemGroup>
33 <Reference Include="System" />
34 <Reference Include="System" />
34 <Reference Include="nunit.framework">
35 <Reference Include="nunit.framework">
35 <HintPath>..\..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll</HintPath>
36 <HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
36 </Reference>
37 </Reference>
37 </ItemGroup>
38 </ItemGroup>
38 <ItemGroup>
39 <ItemGroup>
39 <Compile Include="JsonTests.cs" />
40 <Compile Include="JsonTests.cs" />
40 </ItemGroup>
41 </ItemGroup>
41 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
42 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
42 <ItemGroup>
43 <ItemGroup>
44 <ProjectReference Include="..\..\Implab\Implab.csproj">
45 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
46 <Name>Implab</Name>
47 </ProjectReference>
48 </ItemGroup>
49 <ItemGroup>
43 <None Include="packages.config" />
50 <None Include="packages.config" />
44 </ItemGroup>
51 </ItemGroup>
45 </Project> No newline at end of file
52 </Project>
@@ -1,12 +1,88
1 using NUnit.Framework;
1 using NUnit.Framework;
2 using System;
2 using System;
3 using Implab.Formats.JSON;
4 using Implab.Automaton;
3
5
4 namespace Implab.Format.Test {
6 namespace Implab.Format.Test {
5 [TestFixture()]
7 [TestFixture]
6 public class JsonTests {
8 public class JsonTests {
7 [Test()]
9 [Test]
8 public void TestCase() {
10 public void TestScannerValidTokens() {
11 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
12
13 Tuple<JsonTokenType,object>[] expexted = {
14 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
15 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
16 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
17 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
28 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
29 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
30 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
31 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
32 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
33 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
34 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
35 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
36 };
37
38 object value;
39 JsonTokenType tokenType;
40 for (var i = 0; i < expexted.Length; i++) {
41
42 Assert.IsTrue(scanner.ReadToken(out value, out tokenType));
43 Assert.AreEqual(expexted[i].Item1, tokenType);
44 Assert.AreEqual(expexted[i].Item2, value);
45 }
46
47 Assert.IsFalse(scanner.ReadToken(out value, out tokenType));
48 }
49 }
50
51 [Test]
52 public void TestScannerBadTokens() {
53 var bad = new [] {
54 " 1",
55 " literal",
56 " \"",
57 "\"unclosed string",
58 "1.bad",
59 "001", // should be read as three numbers
60 "--10",
61 "+10",
62 "1.0.0",
63 "1e1.0",
64 "l1teral0",
65 ".123",
66 "-.123"
67 };
68
69 foreach (var json in bad)
70 using (var scanner = new JSONScanner(json)) {
71 try {
72 object value;
73 JsonTokenType token;
74 scanner.ReadToken(out value, out token);
75 if (!Object.Equals(value,json)) {
76 Console.WriteLine("'{0}' is read as {1}", json, value is String ? String.Format("'{0}'", value) : value );
77 continue;
78 }
79 Assert.Fail("Token '{0}' shouldn't pass", json);
80 } catch (ParserException e) {
81 Console.WriteLine(e.Message);
82 }
83 }
84
9 }
85 }
10 }
86 }
11 }
87 }
12
88
@@ -1,4 +1,4
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <packages>
2 <packages>
3 <package id="NUnit" version="3.0.1" targetFramework="net45" />
3 <package id="NUnit" version="2.6.4" targetFramework="net45" />
4 </packages> No newline at end of file
4 </packages>
@@ -1,82 +1,84
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
8 <ProjectGuid>{63F92C0C-61BF-48C0-A377-8D67C3C661D0}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Implab.Test</RootNamespace>
11 <RootNamespace>Implab.Test</RootNamespace>
12 <AssemblyName>Implab.Test</AssemblyName>
12 <AssemblyName>Implab.Test</AssemblyName>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
14 <FileAlignment>512</FileAlignment>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
15 <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16 <TargetFrameworkProfile />
16 <TargetFrameworkProfile />
17 </PropertyGroup>
17 </PropertyGroup>
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
19 <DebugSymbols>true</DebugSymbols>
19 <DebugSymbols>true</DebugSymbols>
20 <DebugType>full</DebugType>
20 <DebugType>full</DebugType>
21 <Optimize>false</Optimize>
21 <Optimize>false</Optimize>
22 <OutputPath>bin\Debug\</OutputPath>
22 <OutputPath>bin\Debug\</OutputPath>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
23 <DefineConstants>DEBUG;TRACE</DefineConstants>
24 <ErrorReport>prompt</ErrorReport>
24 <ErrorReport>prompt</ErrorReport>
25 <WarningLevel>4</WarningLevel>
25 <WarningLevel>4</WarningLevel>
26 <Prefer32Bit>false</Prefer32Bit>
26 <Prefer32Bit>false</Prefer32Bit>
27 </PropertyGroup>
27 </PropertyGroup>
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29 <DebugType>pdbonly</DebugType>
29 <DebugType>pdbonly</DebugType>
30 <Optimize>true</Optimize>
30 <Optimize>true</Optimize>
31 <OutputPath>bin\Release\</OutputPath>
31 <OutputPath>bin\Release\</OutputPath>
32 <DefineConstants>TRACE</DefineConstants>
32 <DefineConstants>TRACE</DefineConstants>
33 <ErrorReport>prompt</ErrorReport>
33 <ErrorReport>prompt</ErrorReport>
34 <WarningLevel>4</WarningLevel>
34 <WarningLevel>4</WarningLevel>
35 <Prefer32Bit>false</Prefer32Bit>
35 <Prefer32Bit>false</Prefer32Bit>
36 </PropertyGroup>
36 </PropertyGroup>
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
37 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
38 <DebugSymbols>true</DebugSymbols>
38 <DebugSymbols>true</DebugSymbols>
39 <DebugType>full</DebugType>
39 <DebugType>full</DebugType>
40 <Optimize>false</Optimize>
40 <Optimize>false</Optimize>
41 <OutputPath>bin\Debug\</OutputPath>
41 <OutputPath>bin\Debug\</OutputPath>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
42 <DefineConstants>DEBUG;TRACE</DefineConstants>
43 <ErrorReport>prompt</ErrorReport>
43 <ErrorReport>prompt</ErrorReport>
44 <WarningLevel>4</WarningLevel>
44 <WarningLevel>4</WarningLevel>
45 <Prefer32Bit>false</Prefer32Bit>
45 <Prefer32Bit>false</Prefer32Bit>
46 </PropertyGroup>
46 </PropertyGroup>
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
47 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
48 <DebugType>pdbonly</DebugType>
48 <DebugType>pdbonly</DebugType>
49 <Optimize>true</Optimize>
49 <Optimize>true</Optimize>
50 <OutputPath>bin\Release\</OutputPath>
50 <OutputPath>bin\Release\</OutputPath>
51 <DefineConstants>TRACE</DefineConstants>
51 <DefineConstants>TRACE</DefineConstants>
52 <ErrorReport>prompt</ErrorReport>
52 <ErrorReport>prompt</ErrorReport>
53 <WarningLevel>4</WarningLevel>
53 <WarningLevel>4</WarningLevel>
54 <Prefer32Bit>false</Prefer32Bit>
54 <Prefer32Bit>false</Prefer32Bit>
55 </PropertyGroup>
55 </PropertyGroup>
56 <ItemGroup>
56 <ItemGroup>
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
57 <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
58 <Reference Include="System" />
58 <Reference Include="System" />
59 <Reference Include="System.Core">
59 <Reference Include="System.Core">
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
60 <RequiredTargetFramework>3.5</RequiredTargetFramework>
61 </Reference>
61 </Reference>
62 </ItemGroup>
62 </ItemGroup>
63 <ItemGroup>
63 <ItemGroup>
64 <Compile Include="AsyncTests.cs" />
64 <Compile Include="AsyncTests.cs" />
65 <Compile Include="CancelationTests.cs" />
65 <Compile Include="PromiseHelper.cs" />
66 <Compile Include="PromiseHelper.cs" />
66 <Compile Include="Properties\AssemblyInfo.cs" />
67 <Compile Include="Properties\AssemblyInfo.cs" />
68 <Compile Include="RunnableComponentTests.cs" />
67 </ItemGroup>
69 </ItemGroup>
68 <ItemGroup>
70 <ItemGroup>
69 <ProjectReference Include="..\Implab\Implab.csproj">
71 <ProjectReference Include="..\Implab\Implab.csproj">
70 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
72 <Project>{99B95D0D-9CF9-4F70-8ADF-F4D0AA5CB0D9}</Project>
71 <Name>Implab</Name>
73 <Name>Implab</Name>
72 </ProjectReference>
74 </ProjectReference>
73 </ItemGroup>
75 </ItemGroup>
74 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
76 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
75 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
77 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
76 Other similar extension points exist, see Microsoft.Common.targets.
78 Other similar extension points exist, see Microsoft.Common.targets.
77 <Target Name="BeforeBuild">
79 <Target Name="BeforeBuild">
78 </Target>
80 </Target>
79 <Target Name="AfterBuild">
81 <Target Name="AfterBuild">
80 </Target>
82 </Target>
81 -->
83 -->
82 </Project> No newline at end of file
84 </Project>
@@ -1,68 +1,69
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{2BD05F84-E067-4B87-9477-FDC2676A21C6}</ProjectGuid>
8 <ProjectGuid>{2BD05F84-E067-4B87-9477-FDC2676A21C6}</ProjectGuid>
9 <OutputType>Library</OutputType>
9 <OutputType>Library</OutputType>
10 <RootNamespace>Implab.Test</RootNamespace>
10 <RootNamespace>Implab.Test</RootNamespace>
11 <AssemblyName>Implab.Test</AssemblyName>
11 <AssemblyName>Implab.Test</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <ReleaseVersion>0.2</ReleaseVersion>
13 <ReleaseVersion>0.2</ReleaseVersion>
14 </PropertyGroup>
14 </PropertyGroup>
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 <DebugSymbols>true</DebugSymbols>
16 <DebugSymbols>true</DebugSymbols>
17 <DebugType>full</DebugType>
17 <DebugType>full</DebugType>
18 <Optimize>false</Optimize>
18 <Optimize>false</Optimize>
19 <OutputPath>bin\Debug</OutputPath>
19 <OutputPath>bin\Debug</OutputPath>
20 <DefineConstants>DEBUG;MONO</DefineConstants>
20 <DefineConstants>DEBUG;MONO</DefineConstants>
21 <ErrorReport>prompt</ErrorReport>
21 <ErrorReport>prompt</ErrorReport>
22 <WarningLevel>4</WarningLevel>
22 <WarningLevel>4</WarningLevel>
23 <ConsolePause>false</ConsolePause>
23 <ConsolePause>false</ConsolePause>
24 </PropertyGroup>
24 </PropertyGroup>
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 <Optimize>true</Optimize>
26 <Optimize>true</Optimize>
27 <OutputPath>bin\Release</OutputPath>
27 <OutputPath>bin\Release</OutputPath>
28 <ErrorReport>prompt</ErrorReport>
28 <ErrorReport>prompt</ErrorReport>
29 <WarningLevel>4</WarningLevel>
29 <WarningLevel>4</WarningLevel>
30 <ConsolePause>false</ConsolePause>
30 <ConsolePause>false</ConsolePause>
31 <DefineConstants>MONO</DefineConstants>
31 <DefineConstants>MONO</DefineConstants>
32 </PropertyGroup>
32 </PropertyGroup>
33 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
33 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
34 <DebugSymbols>true</DebugSymbols>
34 <DebugSymbols>true</DebugSymbols>
35 <DebugType>full</DebugType>
35 <DebugType>full</DebugType>
36 <Optimize>false</Optimize>
36 <Optimize>false</Optimize>
37 <OutputPath>bin\Debug</OutputPath>
37 <OutputPath>bin\Debug</OutputPath>
38 <DefineConstants>DEBUG;TRACE;NET_4_5;MONO</DefineConstants>
38 <DefineConstants>DEBUG;TRACE;NET_4_5;MONO</DefineConstants>
39 <ErrorReport>prompt</ErrorReport>
39 <ErrorReport>prompt</ErrorReport>
40 <WarningLevel>4</WarningLevel>
40 <WarningLevel>4</WarningLevel>
41 <ConsolePause>false</ConsolePause>
41 <ConsolePause>false</ConsolePause>
42 </PropertyGroup>
42 </PropertyGroup>
43 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
43 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
44 <Optimize>true</Optimize>
44 <Optimize>true</Optimize>
45 <OutputPath>bin\Release</OutputPath>
45 <OutputPath>bin\Release</OutputPath>
46 <DefineConstants>NET_4_5;MONO</DefineConstants>
46 <DefineConstants>NET_4_5;MONO</DefineConstants>
47 <ErrorReport>prompt</ErrorReport>
47 <ErrorReport>prompt</ErrorReport>
48 <WarningLevel>4</WarningLevel>
48 <WarningLevel>4</WarningLevel>
49 <ConsolePause>false</ConsolePause>
49 <ConsolePause>false</ConsolePause>
50 </PropertyGroup>
50 </PropertyGroup>
51 <ItemGroup>
51 <ItemGroup>
52 <Reference Include="System" />
52 <Reference Include="System" />
53 <Reference Include="nunit.framework" />
53 <Reference Include="nunit.framework" />
54 </ItemGroup>
54 </ItemGroup>
55 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
55 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
56 <ItemGroup>
56 <ItemGroup>
57 <Compile Include="AsyncTests.cs" />
57 <Compile Include="AsyncTests.cs" />
58 <Compile Include="PromiseHelper.cs" />
58 <Compile Include="PromiseHelper.cs" />
59 <Compile Include="Properties\AssemblyInfo.cs" />
59 <Compile Include="Properties\AssemblyInfo.cs" />
60 <Compile Include="CancelationTests.cs" />
60 <Compile Include="CancelationTests.cs" />
61 <Compile Include="RunnableComponentTests.cs" />
61 </ItemGroup>
62 </ItemGroup>
62 <ItemGroup>
63 <ItemGroup>
63 <ProjectReference Include="..\Implab\Implab.csproj">
64 <ProjectReference Include="..\Implab\Implab.csproj">
64 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
65 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
65 <Name>Implab</Name>
66 <Name>Implab</Name>
66 </ProjectReference>
67 </ProjectReference>
67 </ItemGroup>
68 </ItemGroup>
68 </Project> No newline at end of file
69 </Project>
@@ -1,304 +1,300
1 using System;
1 using System;
2 using Implab.Parallels;
2 using Implab.Parallels;
3 using System.Threading;
3 using System.Threading;
4 using System.Reflection;
4 using System.Reflection;
5
5
6 namespace Implab {
6 namespace Implab {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
8
8
9 const int UNRESOLVED_SATE = 0;
9 const int UNRESOLVED_SATE = 0;
10 const int TRANSITIONAL_STATE = 1;
10 const int TRANSITIONAL_STATE = 1;
11 protected const int SUCCEEDED_STATE = 2;
11 protected const int SUCCEEDED_STATE = 2;
12 protected const int REJECTED_STATE = 3;
12 protected const int REJECTED_STATE = 3;
13 protected const int CANCELLED_STATE = 4;
13 protected const int CANCELLED_STATE = 4;
14
14
15 const int CANCEL_NOT_REQUESTED = 0;
15 const int CANCEL_NOT_REQUESTED = 0;
16 const int CANCEL_REQUESTING = 1;
16 const int CANCEL_REQUESTING = 1;
17 const int CANCEL_REQUESTED = 2;
17 const int CANCEL_REQUESTED = 2;
18
18
19 const int RESERVED_HANDLERS_COUNT = 4;
19 const int RESERVED_HANDLERS_COUNT = 4;
20
20
21 int m_state;
21 int m_state;
22 Exception m_error;
22 Exception m_error;
23 int m_handlersCount;
23 int m_handlersCount;
24
24
25 //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
25 //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
26 THandler[] m_handlers;
26 THandler[] m_handlers;
27 MTQueue<THandler> m_extraHandlers;
27 MTQueue<THandler> m_extraHandlers;
28 int m_handlerPointer = -1;
28 int m_handlerPointer = -1;
29 int m_handlersCommited;
29 int m_handlersCommited;
30
30
31 int m_cancelRequest;
31 int m_cancelRequest;
32 Exception m_cancelationReason;
32 Exception m_cancelationReason;
33 MTQueue<Action<Exception>> m_cancelationHandlers;
33 MTQueue<Action<Exception>> m_cancelationHandlers;
34
34
35
35
36 #region state managment
36 #region state managment
37 bool BeginTransit() {
37 bool BeginTransit() {
38 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
38 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
39 }
39 }
40
40
41 void CompleteTransit(int state) {
41 void CompleteTransit(int state) {
42 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
42 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
43 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
43 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
44 }
44 }
45
45
46 void WaitTransition() {
46 void WaitTransition() {
47 while (m_state == TRANSITIONAL_STATE) {
47 while (m_state == TRANSITIONAL_STATE) {
48 Thread.MemoryBarrier();
48 Thread.MemoryBarrier();
49 }
49 }
50 }
50 }
51
51
52 protected bool BeginSetResult() {
52 protected bool BeginSetResult() {
53 if (!BeginTransit()) {
53 if (!BeginTransit()) {
54 WaitTransition();
54 WaitTransition();
55 if (m_state != CANCELLED_STATE)
55 if (m_state != CANCELLED_STATE)
56 throw new InvalidOperationException("The promise is already resolved");
56 throw new InvalidOperationException("The promise is already resolved");
57 return false;
57 return false;
58 }
58 }
59 return true;
59 return true;
60 }
60 }
61
61
62 protected void EndSetResult() {
62 protected void EndSetResult() {
63 CompleteTransit(SUCCEEDED_STATE);
63 CompleteTransit(SUCCEEDED_STATE);
64 Signal();
64 Signal();
65 }
65 }
66
66
67
67
68
68
69 /// <summary>
69 /// <summary>
70 /// Выполняет обещание, сообщая об ошибке
70 /// Выполняет обещание, сообщая об ошибке
71 /// </summary>
71 /// </summary>
72 /// <remarks>
72 /// <remarks>
73 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
73 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
74 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
74 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
75 /// будут проигнорированы.
75 /// будут проигнорированы.
76 /// </remarks>
76 /// </remarks>
77 /// <param name="error">Исключение возникшее при выполнении операции</param>
77 /// <param name="error">Исключение возникшее при выполнении операции</param>
78 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
78 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
79 protected void SetError(Exception error) {
79 protected void SetError(Exception error) {
80 if (BeginTransit()) {
80 if (BeginTransit()) {
81 if (error is OperationCanceledException) {
81 m_error = error;
82 m_error = error.InnerException;
82 CompleteTransit(REJECTED_STATE);
83 CompleteTransit(CANCELLED_STATE);
83
84 } else {
85 m_error = error is PromiseTransientException ? error.InnerException : error;
86 CompleteTransit(REJECTED_STATE);
87 }
88 Signal();
84 Signal();
89 } else {
85 } else {
90 WaitTransition();
86 WaitTransition();
91 if (m_state == SUCCEEDED_STATE)
87 if (m_state == SUCCEEDED_STATE)
92 throw new InvalidOperationException("The promise is already resolved");
88 throw new InvalidOperationException("The promise is already resolved");
93 }
89 }
94 }
90 }
95
91
96 /// <summary>
92 /// <summary>
97 /// Отменяет операцию, если это возможно.
93 /// Отменяет операцию, если это возможно.
98 /// </summary>
94 /// </summary>
99 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
95 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
100 protected void SetCancelled(Exception reason) {
96 protected void SetCancelled(Exception reason) {
101 if (BeginTransit()) {
97 if (BeginTransit()) {
102 m_error = reason;
98 m_error = reason;
103 CompleteTransit(CANCELLED_STATE);
99 CompleteTransit(CANCELLED_STATE);
104 Signal();
100 Signal();
105 }
101 }
106 }
102 }
107
103
108 protected abstract void SignalHandler(THandler handler, int signal);
104 protected abstract void SignalHandler(THandler handler, int signal);
109
105
110 void Signal() {
106 void Signal() {
111 var hp = m_handlerPointer;
107 var hp = m_handlerPointer;
112 var slot = hp +1 ;
108 var slot = hp +1 ;
113 while (slot < m_handlersCommited) {
109 while (slot < m_handlersCommited) {
114 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
110 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
115 SignalHandler(m_handlers[slot], m_state);
111 SignalHandler(m_handlers[slot], m_state);
116 }
112 }
117 hp = m_handlerPointer;
113 hp = m_handlerPointer;
118 slot = hp +1 ;
114 slot = hp +1 ;
119 }
115 }
120
116
121
117
122 if (m_extraHandlers != null) {
118 if (m_extraHandlers != null) {
123 THandler handler;
119 THandler handler;
124 while (m_extraHandlers.TryDequeue(out handler))
120 while (m_extraHandlers.TryDequeue(out handler))
125 SignalHandler(handler, m_state);
121 SignalHandler(handler, m_state);
126 }
122 }
127 }
123 }
128
124
129 #endregion
125 #endregion
130
126
131 protected abstract Signal GetResolveSignal();
127 protected abstract Signal GetResolveSignal();
132
128
133 #region synchronization traits
129 #region synchronization traits
134 protected void WaitResult(int timeout) {
130 protected void WaitResult(int timeout) {
135 if (!(IsResolved || GetResolveSignal().Wait(timeout)))
131 if (!(IsResolved || GetResolveSignal().Wait(timeout)))
136 throw new TimeoutException();
132 throw new TimeoutException();
137
133
138 switch (m_state) {
134 switch (m_state) {
139 case SUCCEEDED_STATE:
135 case SUCCEEDED_STATE:
140 return;
136 return;
141 case CANCELLED_STATE:
137 case CANCELLED_STATE:
142 throw new OperationCanceledException();
138 throw new OperationCanceledException("The operation has been cancelled", m_error);
143 case REJECTED_STATE:
139 case REJECTED_STATE:
144 throw new TargetInvocationException(m_error);
140 throw new TargetInvocationException(m_error);
145 default:
141 default:
146 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
142 throw new ApplicationException(String.Format("The promise state {0} is invalid", m_state));
147 }
143 }
148 }
144 }
149 #endregion
145 #endregion
150
146
151 #region handlers managment
147 #region handlers managment
152
148
153 protected void AddHandler(THandler handler) {
149 protected void AddHandler(THandler handler) {
154
150
155 if (m_state > 1) {
151 if (m_state > 1) {
156 // the promise is in the resolved state, just invoke the handler
152 // the promise is in the resolved state, just invoke the handler
157 SignalHandler(handler, m_state);
153 SignalHandler(handler, m_state);
158 } else {
154 } else {
159 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
155 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
160
156
161 if (slot < RESERVED_HANDLERS_COUNT) {
157 if (slot < RESERVED_HANDLERS_COUNT) {
162
158
163 if (slot == 0) {
159 if (slot == 0) {
164 m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
160 m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
165 } else {
161 } else {
166 while (m_handlers == null)
162 while (m_handlers == null)
167 Thread.MemoryBarrier();
163 Thread.MemoryBarrier();
168 }
164 }
169
165
170 m_handlers[slot] = handler;
166 m_handlers[slot] = handler;
171
167
172 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
168 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
173 }
169 }
174
170
175 if (m_state > 1) {
171 if (m_state > 1) {
176 do {
172 do {
177 var hp = m_handlerPointer;
173 var hp = m_handlerPointer;
178 slot = hp + 1;
174 slot = hp + 1;
179 if (slot < m_handlersCommited) {
175 if (slot < m_handlersCommited) {
180 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
176 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
181 continue;
177 continue;
182 SignalHandler(m_handlers[slot], m_state);
178 SignalHandler(m_handlers[slot], m_state);
183 }
179 }
184 break;
180 break;
185 } while(true);
181 } while(true);
186 }
182 }
187 } else {
183 } else {
188 if (slot == RESERVED_HANDLERS_COUNT) {
184 if (slot == RESERVED_HANDLERS_COUNT) {
189 m_extraHandlers = new MTQueue<THandler>();
185 m_extraHandlers = new MTQueue<THandler>();
190 } else {
186 } else {
191 while (m_extraHandlers == null)
187 while (m_extraHandlers == null)
192 Thread.MemoryBarrier();
188 Thread.MemoryBarrier();
193 }
189 }
194
190
195 m_extraHandlers.Enqueue(handler);
191 m_extraHandlers.Enqueue(handler);
196
192
197 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
193 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
198 // if the promise have been resolved while we was adding the handler to the queue
194 // if the promise have been resolved while we was adding the handler to the queue
199 // we can't guarantee that someone is still processing it
195 // we can't guarantee that someone is still processing it
200 // therefore we need to fetch a handler from the queue and execute it
196 // therefore we need to fetch a handler from the queue and execute it
201 // note that fetched handler may be not the one that we have added
197 // note that fetched handler may be not the one that we have added
202 // even we can fetch no handlers at all :)
198 // even we can fetch no handlers at all :)
203 SignalHandler(handler, m_state);
199 SignalHandler(handler, m_state);
204 }
200 }
205 }
201 }
206 }
202 }
207
203
208 #endregion
204 #endregion
209
205
210 #region IPromise implementation
206 #region IPromise implementation
211
207
212 public bool IsResolved {
208 public bool IsResolved {
213 get {
209 get {
214 Thread.MemoryBarrier();
210 Thread.MemoryBarrier();
215 return m_state > 1;
211 return m_state > 1;
216 }
212 }
217 }
213 }
218
214
219 public bool IsCancelled {
215 public bool IsCancelled {
220 get {
216 get {
221 Thread.MemoryBarrier();
217 Thread.MemoryBarrier();
222 return m_state == CANCELLED_STATE;
218 return m_state == CANCELLED_STATE;
223 }
219 }
224 }
220 }
225
221
226 #endregion
222 #endregion
227
223
228 public Exception Error {
224 public Exception Error {
229 get {
225 get {
230 return m_error;
226 return m_error;
231 }
227 }
232 }
228 }
233
229
234 public bool CancelOperationIfRequested() {
230 public bool CancelOperationIfRequested() {
235 if (IsCancellationRequested) {
231 if (IsCancellationRequested) {
236 CancelOperation(CancellationReason);
232 CancelOperation(CancellationReason);
237 return true;
233 return true;
238 }
234 }
239 return false;
235 return false;
240 }
236 }
241
237
242 public virtual void CancelOperation(Exception reason) {
238 public virtual void CancelOperation(Exception reason) {
243 SetCancelled(reason);
239 SetCancelled(reason);
244 }
240 }
245
241
246 public void CancellationRequested(Action<Exception> handler) {
242 public void CancellationRequested(Action<Exception> handler) {
247 Safe.ArgumentNotNull(handler, "handler");
243 Safe.ArgumentNotNull(handler, "handler");
248 if (IsCancellationRequested)
244 if (IsCancellationRequested)
249 handler(CancellationReason);
245 handler(CancellationReason);
250
246
251 if (m_cancelationHandlers == null)
247 if (m_cancelationHandlers == null)
252 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
248 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
253
249
254 m_cancelationHandlers.Enqueue(handler);
250 m_cancelationHandlers.Enqueue(handler);
255
251
256 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
252 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
257 // TryDeque implies MemoryBarrier()
253 // TryDeque implies MemoryBarrier()
258 handler(m_cancelationReason);
254 handler(m_cancelationReason);
259 }
255 }
260
256
261 public bool IsCancellationRequested {
257 public bool IsCancellationRequested {
262 get {
258 get {
263 do {
259 do {
264 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
260 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
265 return false;
261 return false;
266 if (m_cancelRequest == CANCEL_REQUESTED)
262 if (m_cancelRequest == CANCEL_REQUESTED)
267 return true;
263 return true;
268 Thread.MemoryBarrier();
264 Thread.MemoryBarrier();
269 } while(true);
265 } while(true);
270 }
266 }
271 }
267 }
272
268
273 public Exception CancellationReason {
269 public Exception CancellationReason {
274 get {
270 get {
275 do {
271 do {
276 Thread.MemoryBarrier();
272 Thread.MemoryBarrier();
277 } while(m_cancelRequest == CANCEL_REQUESTING);
273 } while(m_cancelRequest == CANCEL_REQUESTING);
278
274
279 return m_cancelationReason;
275 return m_cancelationReason;
280 }
276 }
281 }
277 }
282
278
283 #region ICancellable implementation
279 #region ICancellable implementation
284
280
285 public void Cancel() {
281 public void Cancel() {
286 Cancel(null);
282 Cancel(null);
287 }
283 }
288
284
289 public void Cancel(Exception reason) {
285 public void Cancel(Exception reason) {
290 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
286 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
291 m_cancelationReason = reason;
287 m_cancelationReason = reason;
292 m_cancelRequest = CANCEL_REQUESTED;
288 m_cancelRequest = CANCEL_REQUESTED;
293 if (m_cancelationHandlers != null) {
289 if (m_cancelationHandlers != null) {
294 Action<Exception> handler;
290 Action<Exception> handler;
295 while (m_cancelationHandlers.TryDequeue(out handler))
291 while (m_cancelationHandlers.TryDequeue(out handler))
296 handler(m_cancelationReason);
292 handler(m_cancelationReason);
297 }
293 }
298 }
294 }
299 }
295 }
300
296
301 #endregion
297 #endregion
302 }
298 }
303 }
299 }
304
300
@@ -1,142 +1,142
1 using System;
1 using System;
2 using Implab.Parallels;
2 using Implab.Parallels;
3
3
4 namespace Implab {
4 namespace Implab {
5 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise {
5 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise {
6 public struct HandlerDescriptor {
6 public struct HandlerDescriptor {
7 readonly Action m_handler;
7 readonly Action m_handler;
8 readonly Action<Exception> m_error;
8 readonly Action<Exception> m_error;
9 readonly Action<Exception> m_cancel;
9 readonly Action<Exception> m_cancel;
10 readonly PromiseEventType m_mask;
10 readonly PromiseEventType m_mask;
11
11
12 public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) {
12 public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) {
13 m_handler = success;
13 m_handler = success;
14 m_error = error;
14 m_error = error;
15 m_cancel = cancel;
15 m_cancel = cancel;
16 m_mask = PromiseEventType.Success;
16 m_mask = PromiseEventType.Success;
17 }
17 }
18
18
19 public HandlerDescriptor(Action handler, PromiseEventType mask) {
19 public HandlerDescriptor(Action handler, PromiseEventType mask) {
20 m_handler = handler;
20 m_handler = handler;
21 m_error = null;
21 m_error = null;
22 m_cancel = null;
22 m_cancel = null;
23 m_mask = mask;
23 m_mask = mask;
24 }
24 }
25
25
26 public void SignalSuccess() {
26 public void SignalSuccess() {
27 if ((m_mask & PromiseEventType.Success) != 0 && m_handler != null) {
27 if ((m_mask & PromiseEventType.Success) != 0 && m_handler != null) {
28 try {
28 try {
29 m_handler();
29 m_handler();
30 } catch (Exception err) {
30 } catch (Exception err) {
31 // avoid calling handler twice in case of error
31 // avoid calling handler twice in case of error
32 if (m_error != null)
32 if (m_error != null)
33 SignalError(err);
33 SignalError(err);
34 }
34 }
35 }
35 }
36 }
36 }
37
37
38 public void SignalError(Exception err) {
38 public void SignalError(Exception err) {
39 if (m_error != null) {
39 if (m_error != null) {
40 try {
40 try {
41 m_error(err);
41 m_error(err);
42 // Analysis disable once EmptyGeneralCatchClause
42 // Analysis disable once EmptyGeneralCatchClause
43 } catch {
43 } catch {
44 }
44 }
45 } else if ((m_mask & PromiseEventType.Error ) != 0 && m_handler != null) {
45 } else if ((m_mask & PromiseEventType.Error ) != 0 && m_handler != null) {
46 try {
46 try {
47 m_handler();
47 m_handler();
48 // Analysis disable once EmptyGeneralCatchClause
48 // Analysis disable once EmptyGeneralCatchClause
49 } catch {
49 } catch {
50 }
50 }
51 }
51 }
52 }
52 }
53
53
54 public void SignalCancel(Exception reason) {
54 public void SignalCancel(Exception reason) {
55 if (m_cancel != null) {
55 if (m_cancel != null) {
56 try {
56 try {
57 m_cancel(reason);
57 m_cancel(reason);
58 } catch (Exception err) {
58 } catch (Exception err) {
59 SignalError(err);
59 SignalError(err);
60 }
60 }
61 } else if ( (m_mask & PromiseEventType.Cancelled) != 0 && m_handler != null) {
61 } else if ( (m_mask & PromiseEventType.Cancelled) != 0 && m_handler != null) {
62 try {
62 try {
63 m_handler();
63 m_handler();
64 // Analysis disable once EmptyGeneralCatchClause
64 // Analysis disable once EmptyGeneralCatchClause
65 } catch {
65 } catch {
66 }
66 }
67 }
67 }
68 }
68 }
69 }
69 }
70
70
71
71
72 #region implemented abstract members of AbstractPromise
72 #region implemented abstract members of AbstractPromise
73
73
74 protected override void SignalHandler(HandlerDescriptor handler, int signal) {
74 protected override void SignalHandler(HandlerDescriptor handler, int signal) {
75 switch (signal) {
75 switch (signal) {
76 case SUCCEEDED_STATE:
76 case SUCCEEDED_STATE:
77 handler.SignalSuccess();
77 handler.SignalSuccess();
78 break;
78 break;
79 case REJECTED_STATE:
79 case REJECTED_STATE:
80 handler.SignalError(Error);
80 handler.SignalError(Error);
81 break;
81 break;
82 case CANCELLED_STATE:
82 case CANCELLED_STATE:
83 handler.SignalCancel(CancellationReason);
83 handler.SignalCancel(CancellationReason);
84 break;
84 break;
85 default:
85 default:
86 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal));
86 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal));
87 }
87 }
88 }
88 }
89
89
90 protected override Signal GetResolveSignal() {
90 protected override Signal GetResolveSignal() {
91 var signal = new Signal();
91 var signal = new Signal();
92 On(signal.Set, PromiseEventType.All);
92 On(signal.Set, PromiseEventType.All);
93 return signal;
93 return signal;
94 }
94 }
95
95
96 #endregion
96 #endregion
97
97
98 public Type PromiseType {
98 public Type PromiseType {
99 get {
99 get {
100 return typeof(void);
100 return typeof(void);
101 }
101 }
102 }
102 }
103
103
104 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
104 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
105 AddHandler(new HandlerDescriptor(success, error, cancel));
105 AddHandler(new HandlerDescriptor(success, error, cancel));
106 return this;
106 return this;
107 }
107 }
108
108
109 public IPromise On(Action success, Action<Exception> error) {
109 public IPromise On(Action success, Action<Exception> error) {
110 AddHandler(new HandlerDescriptor(success, error, null));
110 AddHandler(new HandlerDescriptor(success, error, null));
111 return this;
111 return this;
112 }
112 }
113
113
114 public IPromise On(Action success) {
114 public IPromise On(Action success) {
115 AddHandler(new HandlerDescriptor(success, null, null));
115 AddHandler(new HandlerDescriptor(success, null, null));
116 return this;
116 return this;
117 }
117 }
118
118
119 public IPromise On(Action handler, PromiseEventType events) {
119 public IPromise On(Action handler, PromiseEventType events) {
120 AddHandler(new HandlerDescriptor(handler,events));
120 AddHandler(new HandlerDescriptor(handler,events));
121 return this;
121 return this;
122 }
122 }
123
123
124 public IPromise<T> Cast<T>() {
124 public IPromise<T> Cast<T>() {
125 throw new InvalidCastException();
125 throw new InvalidCastException();
126 }
126 }
127
127
128 public void Join() {
128 public void Join() {
129 WaitResult(-1);
129 WaitResult(-1);
130 }
130 }
131
131
132 public void Join(int timeout) {
132 public void Join(int timeout) {
133 WaitResult(timeout);
133 WaitResult(timeout);
134 }
134 }
135
135
136 protected void SetResult() {
136 protected void SetResult() {
137 BeginSetResult();
137 if(BeginSetResult())
138 EndSetResult();
138 EndSetResult();
139 }
139 }
140 }
140 }
141 }
141 }
142
142
@@ -1,25 +1,36
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionChainTask : ActionChainTaskBase, IDeferred {
4 public class ActionChainTask : ActionChainTaskBase, IDeferred {
5 readonly Func<IPromise> m_task;
5 readonly Func<IPromise> m_task;
6
6
7 /// <summary>
8 /// Initializes a new instance of the <see cref="Implab.ActionChainTask"/> class.
9 /// </summary>
10 /// <param name="task">The operation which will be performed when the <see cref="Resolve()"/> is called.</param>
11 /// <param name="error">The error handler which will invoke when the <see cref="Reject(Exception)"/> is called or when the task fails with an error.</param>
12 /// <param name="cancel">The cancellation handler.</param>
13 /// <param name="autoCancellable">If set to <c>true</c> will automatically accept
14 /// all cancel requests before the task is started with <see cref="Resolve()"/>,
15 /// after that all requests are directed to the task.</param>
7 public ActionChainTask(Func<IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
16 public ActionChainTask(Func<IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
8 m_task = task;
17 m_task = task;
9 }
18 }
10
19
11 public void Resolve() {
20 public void Resolve() {
12 if (m_task != null && LockCancelation()) {
21 if (m_task != null && LockCancelation()) {
13 try {
22 try {
14 var p = m_task();
23 var p = m_task();
15 p.On(SetResult, HandleErrorInternal, SetCancelled);
24 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
16 CancellationRequested(p.Cancel);
25 CancellationRequested(p.Cancel);
26 } catch (OperationCanceledException reason){
27 HandleCancelInternal(reason);
17 } catch(Exception err) {
28 } catch(Exception err) {
18 HandleErrorInternal(err);
29 HandleErrorInternal(err);
19 }
30 }
20 }
31 }
21 }
32 }
22
33
23 }
34 }
24 }
35 }
25
36
@@ -1,58 +1,62
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3
3
4 namespace Implab {
4 namespace Implab {
5 public class ActionChainTaskBase : AbstractPromise {
5 public class ActionChainTaskBase : AbstractTask {
6 readonly Func<Exception, IPromise> m_error;
6 readonly Func<Exception, IPromise> m_error;
7 readonly Func<Exception, IPromise> m_cancel;
7 readonly Func<Exception, IPromise> m_cancel;
8
8
9 int m_cancelationLock;
10
11 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
9 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) {
12 m_error = error;
10 m_error = error;
13 m_cancel = cancel;
11 m_cancel = cancel;
14 if (autoCancellable)
12 if (autoCancellable)
15 CancellationRequested(CancelOperation);
13 CancellationRequested(CancelOperation);
16 }
14 }
17
15
18 public void Reject(Exception error) {
16 public void Reject(Exception error) {
19 if (LockCancelation())
17 if (LockCancelation())
20 HandleErrorInternal(error);
18 HandleErrorInternal(error);
21 }
19 }
22
20
23
21 public override void CancelOperation(Exception reason) {
22 if (LockCancelation())
23 // отмена вызвана до начала выполнения задачи
24 HandleCancelInternal(reason);
25 }
24
26
25 public override void CancelOperation(Exception reason) {
27 protected void HandleCancelInternal(Exception reason) {
26 if (LockCancelation()) {
28 if (m_cancel != null) {
27 if (m_cancel != null) {
29 try {
28 try {
30 // вызываем обработчик отмены
29 m_cancel(reason).On(SetResult, SetError, SetCancelled);
31 var p = m_cancel(reason);
30 } catch (Exception err) {
32 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
31 HandleErrorInternal(err);
33 // сообщаем асинхронной операции, что клиент уже не хочет получать результат
32 }
34 // т.е. если он инициировал отмену, задача отменилась, вызвался обрабочик отмены
33 } else {
35 // отбработчику сообщили, что результат уже не нужен и уже сам обработчик решает
34 SetCancelled(reason);
36 // отдавать ли результат или подтвердить отмену (или вернуть ошибку).
37 CancellationRequested(p.Cancel);
38 } catch (Exception err) {
39 HandleErrorInternal(err);
35 }
40 }
41 } else {
42 HandleErrorInternal(reason ?? new OperationCanceledException());
36 }
43 }
37 }
44 }
38
45
39 protected void HandleErrorInternal(Exception error) {
46 protected void HandleErrorInternal(Exception error) {
40 if (m_error != null) {
47 if (m_error != null) {
41 try {
48 try {
42 var p = m_error(error);
49 var p = m_error(error);
43 p.On(SetResult,SetError,SetCancelled);
50 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
44 CancellationRequested(p.Cancel);
51 CancellationRequested(p.Cancel);
45 } catch (Exception err) {
52 } catch (Exception err) {
46 SetError(err);
53 SetErrorInternal(error);
47 }
54 }
48 } else {
55 } else {
49 SetError(error);
56 SetErrorInternal(error);
50 }
57 }
51 }
58 }
52
59
53 protected bool LockCancelation() {
54 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
55 }
56 }
60 }
57 }
61 }
58
62
@@ -1,25 +1,27
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionChainTask<T> : ActionChainTaskBase, IDeferred<T> {
4 public class ActionChainTask<T> : ActionChainTaskBase, IDeferred<T> {
5 readonly Func<T, IPromise> m_task;
5 readonly Func<T, IPromise> m_task;
6
6
7 public ActionChainTask(Func<T, IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 public ActionChainTask(Func<T, IPromise> task, Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
8 m_task = task;
8 m_task = task;
9 }
9 }
10
10
11 public void Resolve(T value) {
11 public void Resolve(T value) {
12 if (m_task != null && LockCancelation()) {
12 if (m_task != null && LockCancelation()) {
13 try {
13 try {
14 var p = m_task(value);
14 var p = m_task(value);
15 p.On(SetResult, HandleErrorInternal, SetCancelled);
15 p.On(SetResult, HandleErrorInternal, HandleCancelInternal);
16 CancellationRequested(p.Cancel);
16 CancellationRequested(p.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 } catch(Exception err) {
19 } catch(Exception err) {
18 HandleErrorInternal(err);
20 HandleErrorInternal(err);
19 }
21 }
20 }
22 }
21 }
23 }
22
24
23 }
25 }
24 }
26 }
25
27
@@ -1,22 +1,24
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionTask : ActionTaskBase, IDeferred {
4 public class ActionTask : ActionTaskBase, IDeferred {
5 readonly Action m_task;
5 readonly Action m_task;
6 public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
6 public ActionTask(Action task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 m_task = task;
7 m_task = task;
8 }
8 }
9
9
10 public void Resolve() {
10 public void Resolve() {
11 if (m_task != null && LockCancelation()) {
11 if (m_task != null && LockCancelation()) {
12 try {
12 try {
13 m_task();
13 m_task();
14 SetResult();
14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 } catch(Exception err) {
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
18 }
20 }
19 }
21 }
20 }
22 }
21 }
23 }
22
24
@@ -1,57 +1,53
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class ActionTaskBase : AbstractPromise {
4 public class ActionTaskBase : AbstractTask {
6 readonly Action<Exception> m_cancel;
5 readonly Action<Exception> m_cancel;
7 readonly Action<Exception> m_error;
6 readonly Action<Exception> m_error;
8
7
9 int m_cancelationLock;
10
11 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
8 protected ActionTaskBase( Action<Exception> error, Action<Exception> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
14 if (autoCancellable)
11 if (autoCancellable)
15 CancellationRequested(CancelOperation);
12 CancellationRequested(CancelOperation);
16 }
13 }
17
14
18 public void Reject(Exception error) {
15 public void Reject(Exception error) {
19 Safe.ArgumentNotNull(error, "error");
16 Safe.ArgumentNotNull(error, "error");
20 if (LockCancelation())
17 if (LockCancelation())
21 HandleErrorInternal(error);
18 HandleErrorInternal(error);
22 }
19 }
23
20
21 public override void CancelOperation(Exception reason) {
22 if (LockCancelation())
23 HandleCancelInternal(reason);
24 }
25
24 protected void HandleErrorInternal(Exception error) {
26 protected void HandleErrorInternal(Exception error) {
25 if (m_error != null) {
27 if (m_error != null) {
26 try {
28 try {
27 m_error(error);
29 m_error(error);
28 SetResult();
30 SetResult();
29 } catch(Exception err) {
31 } catch(Exception err) {
30 SetError(err);
32 SetErrorInternal(err);
31 }
33 }
32 } else {
34 } else {
33 SetError(error);
35 SetErrorInternal(error);
34 }
36 }
35 }
37 }
36
38
37 public override void CancelOperation(Exception reason) {
39 protected void HandleCancelInternal(Exception error) {
38 if (LockCancelation()) {
40 if (m_cancel != null) {
39 if (m_cancel != null) {
41 try {
40 try {
42 m_cancel(error);
41 m_cancel(reason);
43 SetResult();
42 SetResult();
44 } catch(Exception err) {
43 } catch (Exception err) {
45 HandleErrorInternal(err);
44 HandleErrorInternal(err);
45 }
46 } else {
47 SetCancelled(reason);
48 }
46 }
47 } else {
48 HandleErrorInternal(error ?? new OperationCanceledException());
49 }
49 }
50 }
50 }
51
52 protected bool LockCancelation() {
53 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
54 }
55 }
51 }
56 }
52 }
57
53
@@ -1,22 +1,24
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class ActionTask<T> : ActionTaskBase, IDeferred<T> {
4 public class ActionTask<T> : ActionTaskBase, IDeferred<T> {
5 readonly Action<T> m_task;
5 readonly Action<T> m_task;
6 public ActionTask(Action<T> task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
6 public ActionTask(Action<T> task, Action<Exception> error, Action<Exception> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 m_task = task;
7 m_task = task;
8 }
8 }
9
9
10 public void Resolve(T value) {
10 public void Resolve(T value) {
11 if (m_task != null && LockCancelation()) {
11 if (m_task != null && LockCancelation()) {
12 try {
12 try {
13 m_task(value);
13 m_task(value);
14 SetResult();
14 SetResult();
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
15 } catch(Exception err) {
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
18 }
20 }
19 }
21 }
20 }
22 }
21 }
23 }
22
24
@@ -1,14 +1,24
1 namespace Implab.Components {
1 namespace Implab.Components {
2
2
3 public enum ExecutionState {
3 public enum ExecutionState {
4 Reserved = 0,
4 Undefined = 0,
5 Uninitialized,
5
6 Created,
7
8 Initializing,
9
6 Ready,
10 Ready,
11
7 Starting,
12 Starting,
13
8 Running,
14 Running,
15
9 Stopping,
16 Stopping,
10 Stopped,
17
18 Failed,
19
11 Disposed,
20 Disposed,
12 Failed
21
22 Last = Disposed
13 }
23 }
14 } No newline at end of file
24 }
@@ -1,21 +1,21
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="Init()"/> method. All parameters needed
6 /// then we have to complete it's creation by calling an <see cref="Init()"/> method. All parameters needed
7 /// to complete the initialization must be passed before the calling <see cref="Init()"/>
7 /// to complete the initialization must be passed before the calling <see cref="Init()"/>
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 /// Normally virtual shouldn't be called from the constructor, due to the incomplete object state, but
14 /// 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
15 /// 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.
16 /// of components where cyclic references may take place.
17 /// </remarks>
17 /// </remarks>
18 void Init();
18 void Init();
19 }
19 }
20 }
20 }
21
21
@@ -1,58 +1,257
1 using System;
1 using System;
2 using Implab.Parsing;
3
2
4 namespace Implab.Components {
3 namespace Implab.Components {
5 public class RunnableComponent : Disposable, IRunnable, IInitializable {
4 public abstract class RunnableComponent : IDisposable, IRunnable, IInitializable {
6
5 enum Commands {
6 Ok = 0,
7 Fail,
8 Init,
9 Start,
10 Stop,
11 Dispose,
12 Last = Dispose
13 }
14
15 class StateMachine {
16 static readonly ExecutionState[,] _transitions;
17
18 static StateMachine() {
19 _transitions = new ExecutionState[(int)ExecutionState.Last + 1, (int)Commands.Last + 1];
20
21 Edge(ExecutionState.Created, ExecutionState.Initializing, Commands.Init);
22 Edge(ExecutionState.Created, ExecutionState.Disposed, Commands.Dispose);
23
24 Edge(ExecutionState.Initializing, ExecutionState.Ready, Commands.Ok);
25 Edge(ExecutionState.Initializing, ExecutionState.Failed, Commands.Fail);
26
27 Edge(ExecutionState.Ready, ExecutionState.Starting, Commands.Start);
28 Edge(ExecutionState.Ready, ExecutionState.Disposed, Commands.Dispose);
29
30 Edge(ExecutionState.Starting, ExecutionState.Running, Commands.Ok);
31 Edge(ExecutionState.Starting, ExecutionState.Failed, Commands.Fail);
32 Edge(ExecutionState.Starting, ExecutionState.Stopping, Commands.Stop);
33 Edge(ExecutionState.Starting, ExecutionState.Disposed, Commands.Dispose);
7
34
35 Edge(ExecutionState.Running, ExecutionState.Failed, Commands.Fail);
36 Edge(ExecutionState.Running, ExecutionState.Stopping, Commands.Stop);
37 Edge(ExecutionState.Running, ExecutionState.Disposed, Commands.Dispose);
8
38
39 Edge(ExecutionState.Stopping, ExecutionState.Failed, Commands.Fail);
40 Edge(ExecutionState.Stopping, ExecutionState.Disposed, Commands.Ok);
41
42 Edge(ExecutionState.Failed, ExecutionState.Disposed, Commands.Dispose);
43 }
44
45 static void Edge(ExecutionState s1, ExecutionState s2, Commands cmd) {
46 _transitions[(int)s1, (int)cmd] = s2;
47 }
9
48
10
49 public ExecutionState State {
50 get;
51 private set;
52 }
53
54 public StateMachine(ExecutionState initial) {
55 State = initial;
56 }
57
58 public bool Move(Commands cmd) {
59 var next = _transitions[(int)State, (int)cmd];
60 if (next == ExecutionState.Undefined)
61 return false;
62 State = next;
63 return true;
64 }
65 }
66
11 IPromise m_pending;
67 IPromise m_pending;
12 Exception m_lastError;
68 Exception m_lastError;
13
69
70 readonly StateMachine m_stateMachine;
71
14 protected RunnableComponent(bool initialized) {
72 protected RunnableComponent(bool initialized) {
73 m_stateMachine = new StateMachine(initialized ? ExecutionState.Ready : ExecutionState.Created);
74 }
75
76 protected virtual int DisposeTimeout {
77 get {
78 return 10000;
79 }
80 }
81
82 void ThrowInvalidCommand(Commands cmd) {
83 if (m_stateMachine.State == ExecutionState.Disposed)
84 throw new ObjectDisposedException(ToString());
85
86 throw new InvalidOperationException(String.Format("Commnd {0} is not allowed in the state {1}", cmd, m_stateMachine.State));
87 }
88
89 void Move(Commands cmd) {
90 if (!m_stateMachine.Move(cmd))
91 ThrowInvalidCommand(cmd);
92 }
93
94 void Invoke(Commands cmd, Action action) {
95 lock (m_stateMachine)
96 Move(cmd);
15
97
98 try {
99 action();
100 lock(m_stateMachine)
101 Move(Commands.Ok);
102
103 } catch (Exception err) {
104 lock (m_stateMachine) {
105 Move(Commands.Fail);
106 m_lastError = err;
107 }
108 throw;
109 }
16 }
110 }
17
111
112 IPromise InvokeAsync(Commands cmd, Func<IPromise> action, Action<IPromise, IDeferred> chain) {
113 IPromise promise = null;
114 IPromise prev;
115
116 var task = new ActionChainTask(action, null, null, true);
117
118 lock (m_stateMachine) {
119 Move(cmd);
120
121 prev = m_pending;
122
123 promise = task.Then(
124 () => {
125 lock(m_stateMachine) {
126 if (m_pending == promise) {
127 Move(Commands.Ok);
128 m_pending = null;
129 }
130 }
131 }, e => {
132 lock(m_stateMachine) {
133 if (m_pending == promise) {
134 Move(Commands.Fail);
135 m_pending = null;
136 m_lastError = e;
137 }
138 }
139 throw new PromiseTransientException(e);
140 }
141 );
142
143 m_pending = promise;
144 }
145
146 if (prev == null)
147 task.Resolve();
148 else
149 chain(prev, task);
150
151 return promise;
152 }
153
154
18 #region IInitializable implementation
155 #region IInitializable implementation
19
156
20 public void Init() {
157 public void Init() {
21
158 Invoke(Commands.Init, OnInitialize);
159 }
160
161 protected virtual void OnInitialize() {
22 }
162 }
23
163
24 #endregion
164 #endregion
25
165
26 #region IRunnable implementation
166 #region IRunnable implementation
27
167
28 public IPromise Start() {
168 public IPromise Start() {
29 throw new NotImplementedException();
169 return InvokeAsync(Commands.Start, OnStart, null);
30 }
170 }
31
171
32 protected virtual IPromise OnStart() {
172 protected virtual IPromise OnStart() {
33 return Promise.SUCCESS;
173 return Promise.SUCCESS;
34 }
174 }
35
175
36 protected virtual void Run() {
176 public IPromise Stop() {
177 return InvokeAsync(Commands.Stop, OnStop, StopPending).Then(Dispose);
178 }
179
180 protected virtual IPromise OnStop() {
181 return Promise.SUCCESS;
37 }
182 }
38
183
39 public IPromise Stop() {
184 /// <summary>
40 throw new NotImplementedException();
185 /// Stops the current operation if one exists.
186 /// </summary>
187 /// <param name="current">Current.</param>
188 /// <param name="stop">Stop.</param>
189 protected virtual void StopPending(IPromise current, IDeferred stop) {
190 if (current == null) {
191 stop.Resolve();
192 } else {
193 // связваем текущую операцию с операцией остановки
194 current.On(
195 stop.Resolve, // если текущая операция заверщилась, то можно начинать остановку
196 stop.Reject, // если текущая операция дала ошибку - то все плохо, нельзя продолжать
197 e => stop.Resolve() // если текущая отменилась, то можно начинать остановку
198 );
199 // посылаем текущей операции сигнал остановки
200 current.Cancel();
201 }
41 }
202 }
42
203
43 public ExecutionState State {
204 public ExecutionState State {
44 get {
205 get {
45 throw new NotImplementedException();
206 return m_stateMachine.State;
46 }
207 }
47 }
208 }
48
209
49 public Exception LastError {
210 public Exception LastError {
50 get {
211 get {
51 throw new NotImplementedException();
212 return m_lastError;
52 }
213 }
53 }
214 }
54
215
55 #endregion
216 #endregion
217
218 #region IDisposable implementation
219
220 public void Dispose() {
221 IPromise pending;
222 lock (m_stateMachine) {
223 if (m_stateMachine.State == ExecutionState.Disposed)
224 return;
225
226 Move(Commands.Dispose);
227
228 GC.SuppressFinalize(this);
229
230 pending = m_pending;
231 m_pending = null;
232 }
233 if (pending != null) {
234 pending.Cancel();
235 pending.Timeout(DisposeTimeout).On(
236 () => Dispose(true, null),
237 err => Dispose(true, err),
238 reason => Dispose(true, new OperationCanceledException("The operation is cancelled", reason))
239 );
240 } else {
241 Dispose(true, m_lastError);
242 }
243 }
244
245 ~RunnableComponent() {
246 Dispose(false, null);
247 }
248
249 #endregion
250
251 protected virtual void Dispose(bool disposing, Exception lastError) {
252
253 }
254
56 }
255 }
57 }
256 }
58
257
@@ -1,24 +1,26
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IDeferred {
4 public class FuncChainTask<TResult> : FuncChainTaskBase<TResult>, IDeferred {
5 readonly Func<IPromise<TResult>> m_task;
5 readonly Func<IPromise<TResult>> m_task;
6
6
7 public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
7 public FuncChainTask(Func<IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable)
8 : base(error, cancel, autoCancellable) {
8 : base(error, cancel, autoCancellable) {
9 m_task = task;
9 m_task = task;
10 }
10 }
11
11
12 public void Resolve() {
12 public void Resolve() {
13 if (m_task != null && LockCancelation()) {
13 if (m_task != null && LockCancelation()) {
14 try {
14 try {
15 var operation = m_task();
15 var operation = m_task();
16 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 operation.On(SetResult, HandleErrorInternal, HandleCancelInternal);
17 CancellationRequested(operation.Cancel);
17 CancellationRequested(operation.Cancel);
18 } catch (OperationCanceledException reason) {
19 HandleCancelInternal(reason);
18 } catch (Exception err) {
20 } catch (Exception err) {
19 HandleErrorInternal(err);
21 HandleErrorInternal(err);
20 }
22 }
21 }
23 }
22 }
24 }
23 }
25 }
24 } No newline at end of file
26 }
@@ -1,58 +1,54
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class FuncChainTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncChainTaskBase<TResult> : AbstractTask<TResult> {
6 readonly Func<Exception, IPromise<TResult>> m_error;
5 readonly Func<Exception, IPromise<TResult>> m_error;
7 readonly Func<Exception, IPromise<TResult>> m_cancel;
6 readonly Func<Exception, IPromise<TResult>> m_cancel;
8
7
9 int m_cancelationLock;
10
11 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
8 protected FuncChainTaskBase( Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
14 if (autoCancellable)
11 if (autoCancellable)
15 CancellationRequested(CancelOperation);
12 CancellationRequested(CancelOperation);
16 }
13 }
17
14
18 public void Reject(Exception error) {
15 public void Reject(Exception error) {
19 if (LockCancelation())
16 if (LockCancelation())
20 HandleErrorInternal(error);
17 HandleErrorInternal(error);
21 }
18 }
22
19
23 public override void CancelOperation(Exception reason) {
20 public override void CancelOperation(Exception reason) {
24 if (LockCancelation()) {
21 if (LockCancelation())
25 if (m_cancel != null) {
22 HandleCancelInternal(reason);
26 try {
27 m_cancel(reason).On(SetResult, HandleErrorInternal, SetCancelled);
28 } catch (Exception err) {
29 HandleErrorInternal(err);
30 }
31 } else {
32 SetCancelled(reason);
33 }
34 }
35
36 }
23 }
37
24
38 protected void HandleErrorInternal(Exception error) {
25 protected void HandleErrorInternal(Exception error) {
39 if (m_error != null) {
26 if (m_error != null) {
40 try {
27 try {
41 var operation = m_error(error);
28 var p = m_error(error);
42
29 p.On(SetResult, SetErrorInternal, SetCancelledInternal);
43 operation.On(SetResult, SetError, SetCancelled);
30 CancellationRequested(p.Cancel);
44 CancellationRequested(operation.Cancel);
45 } catch(Exception err) {
31 } catch(Exception err) {
46 SetError(err);
32 SetErrorInternal(err);
47 }
33 }
48 } else {
34 } else {
49 SetError(error);
35 SetErrorInternal(error);
50 }
36 }
51 }
37 }
52
38
53 protected bool LockCancelation() {
39 protected void HandleCancelInternal(Exception reason) {
54 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
40 if (m_cancel != null) {
41 try {
42 var p = m_cancel(reason);
43 p.On(SetResult, HandleErrorInternal, SetCancelledInternal);
44 CancellationRequested(p.Cancel);
45 } catch (Exception err) {
46 HandleErrorInternal(err);
47 }
48 } else {
49 HandleErrorInternal(reason ?? new OperationCanceledException());
50 }
55 }
51 }
56 }
52 }
57 }
53 }
58
54
@@ -1,23 +1,25
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class FuncChainTask<TArg,TResult> : FuncChainTaskBase<TResult>, IDeferred<TArg> {
4 public class FuncChainTask<TArg,TResult> : FuncChainTaskBase<TResult>, IDeferred<TArg> {
5 readonly Func<TArg, IPromise<TResult>> m_task;
5 readonly Func<TArg, IPromise<TResult>> m_task;
6
6
7 public FuncChainTask(Func<TArg, IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) : base(error, cancel, autoCancellable){
7 public FuncChainTask(Func<TArg, IPromise<TResult>> task, Func<Exception, IPromise<TResult>> error, Func<Exception, IPromise<TResult>> cancel, bool autoCancellable) : base(error, cancel, autoCancellable){
8 m_task = task;
8 m_task = task;
9 }
9 }
10
10
11 public void Resolve(TArg value) {
11 public void Resolve(TArg value) {
12 if (m_task != null && LockCancelation()) {
12 if (m_task != null && LockCancelation()) {
13 try {
13 try {
14 var operation = m_task(value);
14 var operation = m_task(value);
15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
15 operation.On(SetResult, HandleErrorInternal, SetCancelled);
16 CancellationRequested(operation.Cancel);
16 CancellationRequested(operation.Cancel);
17 } catch (OperationCanceledException reason) {
18 HandleCancelInternal(reason);
17 } catch (Exception err) {
19 } catch (Exception err) {
18 HandleErrorInternal(err);
20 HandleErrorInternal(err);
19 }
21 }
20 }
22 }
21 }
23 }
22 }
24 }
23 } No newline at end of file
25 }
@@ -1,23 +1,25
1 using System;
1 using System;
2 using System.Threading;
2 using System.Threading;
3
3
4 namespace Implab {
4 namespace Implab {
5 public class FuncTask<T> : FuncTaskBase<T>, IDeferred {
5 public class FuncTask<T> : FuncTaskBase<T>, IDeferred {
6 readonly Func<T> m_task;
6 readonly Func<T> m_task;
7
7
8 public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
8 public FuncTask(Func<T> task, Func<Exception, T> error, Func<Exception, T> cancel, bool autoCancellable) : base(error, cancel, autoCancellable) {
9 m_task = task;
9 m_task = task;
10 }
10 }
11
11
12 public void Resolve() {
12 public void Resolve() {
13 if (m_task != null && LockCancelation()) {
13 if (m_task != null && LockCancelation()) {
14 try {
14 try {
15 SetResult(m_task());
15 SetResult(m_task());
16 } catch(OperationCanceledException reason) {
17 HandleCancelInternal(reason);
16 } catch(Exception err) {
18 } catch(Exception err) {
17 HandleErrorInternal(err);
19 HandleErrorInternal(err);
18 }
20 }
19 }
21 }
20 }
22 }
21 }
23 }
22 }
24 }
23
25
@@ -1,55 +1,52
1 using System;
1 using System;
2 using System.Threading;
3
2
4 namespace Implab {
3 namespace Implab {
5 public class FuncTaskBase<TResult> : AbstractPromise<TResult> {
4 public class FuncTaskBase<TResult> : AbstractTask<TResult> {
6 readonly Func<Exception, TResult> m_cancel;
5 readonly Func<Exception, TResult> m_cancel;
7 readonly Func<Exception, TResult> m_error;
6 readonly Func<Exception, TResult> m_error;
8
7
9 int m_cancelationLock;
10
11 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
8 protected FuncTaskBase( Func<Exception, TResult> error, Func<Exception, TResult> cancel, bool autoCancellable) {
12 m_error = error;
9 m_error = error;
13 m_cancel = cancel;
10 m_cancel = cancel;
14 if (autoCancellable)
11 if (autoCancellable)
15 CancellationRequested(CancelOperation);
12 CancellationRequested(CancelOperation);
16 }
13 }
17
14
18 public void Reject(Exception error) {
15 public void Reject(Exception error) {
19 Safe.ArgumentNotNull(error, "error");
16 Safe.ArgumentNotNull(error, "error");
20 if (LockCancelation())
17 if (LockCancelation())
21 HandleErrorInternal(error);
18 HandleErrorInternal(error);
22 }
19 }
23
20
24 protected void HandleErrorInternal(Exception error) {
21 protected void HandleErrorInternal(Exception error) {
25 if (m_error != null) {
22 if (m_error != null) {
26 try {
23 try {
27 SetResult(m_error(error));
24 SetResult(m_error(error));
28 } catch(Exception err) {
25 } catch(Exception err) {
29 SetError(err);
26 SetErrorInternal(err);
30 }
27 }
31 } else {
28 } else {
32 SetError(error);
29 SetErrorInternal(error);
33 }
30 }
34 }
31 }
35
32
36 public override void CancelOperation(Exception reason) {
33 public override void CancelOperation(Exception reason) {
37 if (LockCancelation()) {
34 if (LockCancelation())
38 if (m_cancel != null) {
35 HandleCancelInternal(reason);
39 try {
36 }
40 SetResult(m_cancel(reason));
37
41 } catch (Exception err) {
38 protected void HandleCancelInternal(Exception reason) {
42 HandleErrorInternal(err);
39 if (m_cancel != null) {
43 }
40 try {
44 } else {
41 SetResult(m_cancel(reason));
45 SetCancelled(reason);
42 } catch (Exception err) {
43 HandleErrorInternal(err);
46 }
44 }
45 } else {
46 HandleErrorInternal(reason ?? new OperationCanceledException());
47 }
47 }
48 }
48 }
49
49
50 protected bool LockCancelation() {
51 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0);
52 }
53 }
50 }
54 }
51 }
55
52
@@ -1,22 +1,24
1 using System;
1 using System;
2
2
3 namespace Implab {
3 namespace Implab {
4 public class FuncTask<TArg, TResult> : FuncTaskBase<TResult>, IDeferred<TArg> {
4 public class FuncTask<TArg, TResult> : FuncTaskBase<TResult>, IDeferred<TArg> {
5 readonly Func<TArg, TResult> m_task;
5 readonly Func<TArg, TResult> m_task;
6
6
7 public FuncTask(Func<TArg, TResult> task, Func<Exception, TResult> error,Func<Exception, TResult> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
7 public FuncTask(Func<TArg, TResult> task, Func<Exception, TResult> error,Func<Exception, TResult> cancel, bool autoCancellable) : base(error,cancel, autoCancellable) {
8 m_task = task;
8 m_task = task;
9 }
9 }
10
10
11 public void Resolve(TArg value) {
11 public void Resolve(TArg value) {
12 if (m_task != null && LockCancelation()) {
12 if (m_task != null && LockCancelation()) {
13 try {
13 try {
14 SetResult(m_task(value));
14 SetResult(m_task(value));
15 } catch (Exception err) {
15 } catch(OperationCanceledException reason) {
16 HandleCancelInternal(reason);
17 } catch(Exception err) {
16 HandleErrorInternal(err);
18 HandleErrorInternal(err);
17 }
19 }
18 }
20 }
19 }
21 }
20 }
22 }
21 }
23 }
22
24
@@ -1,261 +1,276
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 <OutputType>Library</OutputType>
7 <OutputType>Library</OutputType>
8 <RootNamespace>Implab</RootNamespace>
8 <RootNamespace>Implab</RootNamespace>
9 <AssemblyName>Implab</AssemblyName>
9 <AssemblyName>Implab</AssemblyName>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11 <ReleaseVersion>0.2</ReleaseVersion>
12 <ProductVersion>8.0.30703</ProductVersion>
13 <SchemaVersion>2.0</SchemaVersion>
11 </PropertyGroup>
14 </PropertyGroup>
12 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
13 <DebugSymbols>true</DebugSymbols>
16 <DebugSymbols>true</DebugSymbols>
14 <DebugType>full</DebugType>
17 <DebugType>full</DebugType>
15 <Optimize>false</Optimize>
18 <Optimize>false</Optimize>
16 <OutputPath>bin\Debug</OutputPath>
19 <OutputPath>bin\Debug</OutputPath>
17 <DefineConstants>TRACE;DEBUG;</DefineConstants>
20 <DefineConstants>TRACE;DEBUG;</DefineConstants>
18 <ErrorReport>prompt</ErrorReport>
21 <ErrorReport>prompt</ErrorReport>
19 <WarningLevel>4</WarningLevel>
22 <WarningLevel>4</WarningLevel>
20 <ConsolePause>false</ConsolePause>
23 <ConsolePause>false</ConsolePause>
21 <RunCodeAnalysis>true</RunCodeAnalysis>
24 <RunCodeAnalysis>true</RunCodeAnalysis>
22 </PropertyGroup>
25 </PropertyGroup>
23 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24 <DebugType>full</DebugType>
27 <DebugType>full</DebugType>
25 <Optimize>true</Optimize>
28 <Optimize>true</Optimize>
26 <OutputPath>bin\Release</OutputPath>
29 <OutputPath>bin\Release</OutputPath>
27 <ErrorReport>prompt</ErrorReport>
30 <ErrorReport>prompt</ErrorReport>
28 <WarningLevel>4</WarningLevel>
31 <WarningLevel>4</WarningLevel>
29 <ConsolePause>false</ConsolePause>
32 <ConsolePause>false</ConsolePause>
30 </PropertyGroup>
33 </PropertyGroup>
31 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
34 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
32 <DebugSymbols>true</DebugSymbols>
35 <DebugSymbols>true</DebugSymbols>
33 <DebugType>full</DebugType>
36 <DebugType>full</DebugType>
34 <Optimize>false</Optimize>
37 <Optimize>false</Optimize>
35 <OutputPath>bin\Debug</OutputPath>
38 <OutputPath>bin\Debug</OutputPath>
36 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
39 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
37 <ErrorReport>prompt</ErrorReport>
40 <ErrorReport>prompt</ErrorReport>
38 <WarningLevel>4</WarningLevel>
41 <WarningLevel>4</WarningLevel>
39 <RunCodeAnalysis>true</RunCodeAnalysis>
42 <RunCodeAnalysis>true</RunCodeAnalysis>
40 <ConsolePause>false</ConsolePause>
43 <ConsolePause>false</ConsolePause>
41 </PropertyGroup>
44 </PropertyGroup>
42 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
45 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
43 <Optimize>true</Optimize>
46 <Optimize>true</Optimize>
44 <OutputPath>bin\Release</OutputPath>
47 <OutputPath>bin\Release</OutputPath>
45 <ErrorReport>prompt</ErrorReport>
48 <ErrorReport>prompt</ErrorReport>
46 <WarningLevel>4</WarningLevel>
49 <WarningLevel>4</WarningLevel>
47 <ConsolePause>false</ConsolePause>
50 <ConsolePause>false</ConsolePause>
48 <DefineConstants>NET_4_5</DefineConstants>
51 <DefineConstants>NET_4_5</DefineConstants>
49 </PropertyGroup>
52 </PropertyGroup>
50 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
53 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
51 <DebugSymbols>true</DebugSymbols>
54 <DebugSymbols>true</DebugSymbols>
52 <DebugType>full</DebugType>
55 <DebugType>full</DebugType>
53 <Optimize>false</Optimize>
56 <Optimize>false</Optimize>
54 <OutputPath>bin\Debug</OutputPath>
57 <OutputPath>bin\Debug</OutputPath>
55 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
58 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
56 <ErrorReport>prompt</ErrorReport>
59 <ErrorReport>prompt</ErrorReport>
57 <WarningLevel>4</WarningLevel>
60 <WarningLevel>4</WarningLevel>
58 <RunCodeAnalysis>true</RunCodeAnalysis>
61 <RunCodeAnalysis>true</RunCodeAnalysis>
59 <ConsolePause>false</ConsolePause>
62 <ConsolePause>false</ConsolePause>
60 </PropertyGroup>
63 </PropertyGroup>
61 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
64 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
62 <Optimize>true</Optimize>
65 <Optimize>true</Optimize>
63 <OutputPath>bin\Release</OutputPath>
66 <OutputPath>bin\Release</OutputPath>
64 <DefineConstants>NET_4_5;MONO;</DefineConstants>
67 <DefineConstants>NET_4_5;MONO;</DefineConstants>
65 <ErrorReport>prompt</ErrorReport>
68 <ErrorReport>prompt</ErrorReport>
66 <WarningLevel>4</WarningLevel>
69 <WarningLevel>4</WarningLevel>
67 <ConsolePause>false</ConsolePause>
70 <ConsolePause>false</ConsolePause>
68 </PropertyGroup>
71 </PropertyGroup>
69 <ItemGroup>
72 <ItemGroup>
70 <Reference Include="System" />
73 <Reference Include="System" />
71 <Reference Include="System.Xml" />
74 <Reference Include="System.Xml" />
72 <Reference Include="mscorlib" />
75 <Reference Include="mscorlib" />
73 </ItemGroup>
76 </ItemGroup>
74 <ItemGroup>
77 <ItemGroup>
75 <Compile Include="CustomEqualityComparer.cs" />
78 <Compile Include="CustomEqualityComparer.cs" />
76 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
79 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
77 <Compile Include="Diagnostics\EventText.cs" />
80 <Compile Include="Diagnostics\EventText.cs" />
78 <Compile Include="Diagnostics\LogChannel.cs" />
81 <Compile Include="Diagnostics\LogChannel.cs" />
79 <Compile Include="Diagnostics\LogicalOperation.cs" />
82 <Compile Include="Diagnostics\LogicalOperation.cs" />
80 <Compile Include="Diagnostics\TextFileListener.cs" />
83 <Compile Include="Diagnostics\TextFileListener.cs" />
81 <Compile Include="Diagnostics\TraceLog.cs" />
84 <Compile Include="Diagnostics\TraceLog.cs" />
82 <Compile Include="Diagnostics\TraceEvent.cs" />
85 <Compile Include="Diagnostics\TraceEvent.cs" />
83 <Compile Include="Diagnostics\TraceEventType.cs" />
86 <Compile Include="Diagnostics\TraceEventType.cs" />
84 <Compile Include="ICancellable.cs" />
87 <Compile Include="ICancellable.cs" />
85 <Compile Include="IProgressHandler.cs" />
88 <Compile Include="IProgressHandler.cs" />
86 <Compile Include="IProgressNotifier.cs" />
89 <Compile Include="IProgressNotifier.cs" />
87 <Compile Include="IPromiseT.cs" />
90 <Compile Include="IPromiseT.cs" />
88 <Compile Include="IPromise.cs" />
91 <Compile Include="IPromise.cs" />
89 <Compile Include="IServiceLocator.cs" />
92 <Compile Include="IServiceLocator.cs" />
90 <Compile Include="ITaskController.cs" />
93 <Compile Include="ITaskController.cs" />
91 <Compile Include="JSON\JSONElementContext.cs" />
92 <Compile Include="JSON\JSONElementType.cs" />
93 <Compile Include="JSON\JSONGrammar.cs" />
94 <Compile Include="JSON\JSONParser.cs" />
95 <Compile Include="JSON\JSONScanner.cs" />
96 <Compile Include="JSON\JsonTokenType.cs" />
97 <Compile Include="JSON\JSONWriter.cs" />
98 <Compile Include="JSON\JSONXmlReader.cs" />
99 <Compile Include="JSON\JSONXmlReaderOptions.cs" />
100 <Compile Include="JSON\StringTranslator.cs" />
101 <Compile Include="Parallels\DispatchPool.cs" />
94 <Compile Include="Parallels\DispatchPool.cs" />
102 <Compile Include="Parallels\ArrayTraits.cs" />
95 <Compile Include="Parallels\ArrayTraits.cs" />
103 <Compile Include="Parallels\MTQueue.cs" />
96 <Compile Include="Parallels\MTQueue.cs" />
104 <Compile Include="Parallels\WorkerPool.cs" />
97 <Compile Include="Parallels\WorkerPool.cs" />
105 <Compile Include="Parsing\AltToken.cs" />
106 <Compile Include="Parsing\BinaryToken.cs" />
107 <Compile Include="Parsing\CatToken.cs" />
108 <Compile Include="Parsing\CDFADefinition.cs" />
109 <Compile Include="Parsing\DFABuilder.cs" />
110 <Compile Include="Parsing\DFAStateDescriptor.cs" />
111 <Compile Include="Parsing\DFAutomaton.cs" />
112 <Compile Include="Parsing\EDFADefinition.cs" />
113 <Compile Include="Parsing\EmptyToken.cs" />
114 <Compile Include="Parsing\EndToken.cs" />
115 <Compile Include="Parsing\EnumAlphabet.cs" />
116 <Compile Include="Parsing\Grammar.cs" />
117 <Compile Include="Parsing\IAlphabet.cs" />
118 <Compile Include="Parsing\IDFADefinition.cs" />
119 <Compile Include="Parsing\IVisitor.cs" />
120 <Compile Include="Parsing\ParserException.cs" />
121 <Compile Include="Parsing\Scanner.cs" />
122 <Compile Include="Parsing\StarToken.cs" />
123 <Compile Include="Parsing\SymbolToken.cs" />
124 <Compile Include="Parsing\Token.cs" />
125 <Compile Include="ProgressInitEventArgs.cs" />
98 <Compile Include="ProgressInitEventArgs.cs" />
126 <Compile Include="Properties\AssemblyInfo.cs" />
99 <Compile Include="Properties\AssemblyInfo.cs" />
127 <Compile Include="Parallels\AsyncPool.cs" />
100 <Compile Include="Parallels\AsyncPool.cs" />
128 <Compile Include="Safe.cs" />
101 <Compile Include="Safe.cs" />
129 <Compile Include="ValueEventArgs.cs" />
102 <Compile Include="ValueEventArgs.cs" />
130 <Compile Include="PromiseExtensions.cs" />
103 <Compile Include="PromiseExtensions.cs" />
131 <Compile Include="SyncContextPromise.cs" />
104 <Compile Include="SyncContextPromise.cs" />
132 <Compile Include="Diagnostics\OperationContext.cs" />
105 <Compile Include="Diagnostics\OperationContext.cs" />
133 <Compile Include="Diagnostics\TraceContext.cs" />
106 <Compile Include="Diagnostics\TraceContext.cs" />
134 <Compile Include="Diagnostics\LogEventArgs.cs" />
107 <Compile Include="Diagnostics\LogEventArgs.cs" />
135 <Compile Include="Diagnostics\LogEventArgsT.cs" />
108 <Compile Include="Diagnostics\LogEventArgsT.cs" />
136 <Compile Include="Diagnostics\Extensions.cs" />
109 <Compile Include="Diagnostics\Extensions.cs" />
137 <Compile Include="PromiseEventType.cs" />
110 <Compile Include="PromiseEventType.cs" />
138 <Compile Include="Parallels\AsyncQueue.cs" />
111 <Compile Include="Parallels\AsyncQueue.cs" />
139 <Compile Include="PromiseT.cs" />
112 <Compile Include="PromiseT.cs" />
140 <Compile Include="IDeferred.cs" />
113 <Compile Include="IDeferred.cs" />
141 <Compile Include="IDeferredT.cs" />
114 <Compile Include="IDeferredT.cs" />
142 <Compile Include="Promise.cs" />
115 <Compile Include="Promise.cs" />
143 <Compile Include="PromiseTransientException.cs" />
116 <Compile Include="PromiseTransientException.cs" />
144 <Compile Include="Parallels\Signal.cs" />
117 <Compile Include="Parallels\Signal.cs" />
145 <Compile Include="Parallels\SharedLock.cs" />
118 <Compile Include="Parallels\SharedLock.cs" />
146 <Compile Include="Diagnostics\ILogWriter.cs" />
119 <Compile Include="Diagnostics\ILogWriter.cs" />
147 <Compile Include="Diagnostics\ListenerBase.cs" />
120 <Compile Include="Diagnostics\ListenerBase.cs" />
148 <Compile Include="Parallels\BlockingQueue.cs" />
121 <Compile Include="Parallels\BlockingQueue.cs" />
149 <Compile Include="AbstractEvent.cs" />
122 <Compile Include="AbstractEvent.cs" />
150 <Compile Include="AbstractPromise.cs" />
123 <Compile Include="AbstractPromise.cs" />
151 <Compile Include="AbstractPromiseT.cs" />
124 <Compile Include="AbstractPromiseT.cs" />
152 <Compile Include="FuncTask.cs" />
125 <Compile Include="FuncTask.cs" />
153 <Compile Include="FuncTaskBase.cs" />
126 <Compile Include="FuncTaskBase.cs" />
154 <Compile Include="FuncTaskT.cs" />
127 <Compile Include="FuncTaskT.cs" />
155 <Compile Include="ActionChainTaskBase.cs" />
128 <Compile Include="ActionChainTaskBase.cs" />
156 <Compile Include="ActionChainTask.cs" />
129 <Compile Include="ActionChainTask.cs" />
157 <Compile Include="ActionChainTaskT.cs" />
130 <Compile Include="ActionChainTaskT.cs" />
158 <Compile Include="FuncChainTaskBase.cs" />
131 <Compile Include="FuncChainTaskBase.cs" />
159 <Compile Include="FuncChainTask.cs" />
132 <Compile Include="FuncChainTask.cs" />
160 <Compile Include="FuncChainTaskT.cs" />
133 <Compile Include="FuncChainTaskT.cs" />
161 <Compile Include="ActionTaskBase.cs" />
134 <Compile Include="ActionTaskBase.cs" />
162 <Compile Include="ActionTask.cs" />
135 <Compile Include="ActionTask.cs" />
163 <Compile Include="ActionTaskT.cs" />
136 <Compile Include="ActionTaskT.cs" />
164 <Compile Include="ICancellationToken.cs" />
137 <Compile Include="ICancellationToken.cs" />
165 <Compile Include="SuccessPromise.cs" />
138 <Compile Include="SuccessPromise.cs" />
166 <Compile Include="SuccessPromiseT.cs" />
139 <Compile Include="SuccessPromiseT.cs" />
167 <Compile Include="PromiseAwaiterT.cs" />
140 <Compile Include="PromiseAwaiterT.cs" />
168 <Compile Include="PromiseAwaiter.cs" />
141 <Compile Include="PromiseAwaiter.cs" />
169 <Compile Include="Components\ComponentContainer.cs" />
142 <Compile Include="Components\ComponentContainer.cs" />
170 <Compile Include="Components\Disposable.cs" />
143 <Compile Include="Components\Disposable.cs" />
171 <Compile Include="Components\DisposablePool.cs" />
144 <Compile Include="Components\DisposablePool.cs" />
172 <Compile Include="Components\ObjectPool.cs" />
145 <Compile Include="Components\ObjectPool.cs" />
173 <Compile Include="Components\ServiceLocator.cs" />
146 <Compile Include="Components\ServiceLocator.cs" />
174 <Compile Include="Components\IInitializable.cs" />
147 <Compile Include="Components\IInitializable.cs" />
175 <Compile Include="TaskController.cs" />
148 <Compile Include="TaskController.cs" />
176 <Compile Include="Components\App.cs" />
149 <Compile Include="Components\App.cs" />
177 <Compile Include="Components\IRunnable.cs" />
150 <Compile Include="Components\IRunnable.cs" />
178 <Compile Include="Components\ExecutionState.cs" />
151 <Compile Include="Components\ExecutionState.cs" />
179 <Compile Include="Components\RunnableComponent.cs" />
152 <Compile Include="Components\RunnableComponent.cs" />
180 <Compile Include="Components\IFactory.cs" />
153 <Compile Include="Components\IFactory.cs" />
181 <Compile Include="Parsing\DFADefinition.cs" />
154 <Compile Include="Automaton\IAlphabet.cs" />
182 <Compile Include="Parsing\IndexedAlphabetBase.cs" />
155 <Compile Include="Automaton\ParserException.cs" />
183 <Compile Include="Parsing\CharAlphabet.cs" />
156 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
184 <Compile Include="Parsing\IAlphabetBuilder.cs" />
157 <Compile Include="Automaton\IAlphabetBuilder.cs" />
185 <Compile Include="Parsing\IDFADefinitionBuilder.cs" />
158 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
159 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
160 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
161 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
162 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
163 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
164 <Compile Include="Automaton\RegularExpressions\Token.cs" />
165 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
166 <Compile Include="Automaton\AutomatonTransition.cs" />
167 <Compile Include="Formats\JSON\JSONElementContext.cs" />
168 <Compile Include="Formats\JSON\JSONElementType.cs" />
169 <Compile Include="Formats\JSON\JSONGrammar.cs" />
170 <Compile Include="Formats\JSON\JSONParser.cs" />
171 <Compile Include="Formats\JSON\JSONScanner.cs" />
172 <Compile Include="Formats\JSON\JsonTokenType.cs" />
173 <Compile Include="Formats\JSON\JSONWriter.cs" />
174 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
175 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
176 <Compile Include="Formats\JSON\StringTranslator.cs" />
177 <Compile Include="Automaton\MapAlphabet.cs" />
178 <Compile Include="Formats\CharAlphabet.cs" />
179 <Compile Include="Formats\ByteAlphabet.cs" />
180 <Compile Include="Automaton\IDFATable.cs" />
181 <Compile Include="Automaton\IDFATableBuilder.cs" />
182 <Compile Include="Automaton\DFATable.cs" />
183 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
184 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
185 <Compile Include="Formats\TextScanner.cs" />
186 <Compile Include="Formats\StringScanner.cs" />
187 <Compile Include="Formats\ReaderScanner.cs" />
188 <Compile Include="Formats\ScannerContext.cs" />
189 <Compile Include="Formats\Grammar.cs" />
190 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
191 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
192 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
193 <Compile Include="Automaton\AutomatonConst.cs" />
194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
195 <Compile Include="Components\LazyAndWeak.cs" />
196 <Compile Include="AbstractTask.cs" />
197 <Compile Include="AbstractTaskT.cs" />
186 </ItemGroup>
198 </ItemGroup>
187 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
199 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
188 <ItemGroup />
200 <ItemGroup />
189 <ProjectExtensions>
201 <ProjectExtensions>
190 <MonoDevelop>
202 <MonoDevelop>
191 <Properties>
203 <Properties>
192 <Policies>
204 <Policies>
193 <CSharpFormattingPolicy IndentSwitchBody="True" NamespaceBraceStyle="EndOfLine" ClassBraceStyle="EndOfLine" InterfaceBraceStyle="EndOfLine" StructBraceStyle="EndOfLine" EnumBraceStyle="EndOfLine" MethodBraceStyle="EndOfLine" ConstructorBraceStyle="EndOfLine" DestructorBraceStyle="EndOfLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeIndexerDeclarationBracket="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
205 <CSharpFormattingPolicy IndentSwitchBody="True" NamespaceBraceStyle="EndOfLine" ClassBraceStyle="EndOfLine" InterfaceBraceStyle="EndOfLine" StructBraceStyle="EndOfLine" EnumBraceStyle="EndOfLine" MethodBraceStyle="EndOfLine" ConstructorBraceStyle="EndOfLine" DestructorBraceStyle="EndOfLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeIndexerDeclarationBracket="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
194 <TextStylePolicy FileWidth="120" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
206 <TextStylePolicy FileWidth="120" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
195 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
207 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
196 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="application/xml" />
208 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="application/xml" />
197 <XmlFormattingPolicy inheritsSet="Mono" inheritsScope="application/xml" scope="application/xml" />
209 <XmlFormattingPolicy inheritsSet="Mono" inheritsScope="application/xml" scope="application/xml" />
198 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
210 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
199 <NameConventionPolicy>
211 <NameConventionPolicy>
200 <Rules>
212 <Rules>
201 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
213 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
202 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
214 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
203 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
215 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
204 <RequiredPrefixes>
216 <RequiredPrefixes>
205 <String>I</String>
217 <String>I</String>
206 </RequiredPrefixes>
218 </RequiredPrefixes>
207 </NamingRule>
219 </NamingRule>
208 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
220 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
209 <RequiredSuffixes>
221 <RequiredSuffixes>
210 <String>Attribute</String>
222 <String>Attribute</String>
211 </RequiredSuffixes>
223 </RequiredSuffixes>
212 </NamingRule>
224 </NamingRule>
213 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
225 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
214 <RequiredSuffixes>
226 <RequiredSuffixes>
215 <String>EventArgs</String>
227 <String>EventArgs</String>
216 </RequiredSuffixes>
228 </RequiredSuffixes>
217 </NamingRule>
229 </NamingRule>
218 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
230 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
219 <RequiredSuffixes>
231 <RequiredSuffixes>
220 <String>Exception</String>
232 <String>Exception</String>
221 </RequiredSuffixes>
233 </RequiredSuffixes>
222 </NamingRule>
234 </NamingRule>
223 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
235 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
224 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
236 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
225 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
237 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
226 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
238 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
227 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
239 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
228 <RequiredPrefixes>
240 <RequiredPrefixes>
229 <String>m_</String>
241 <String>m_</String>
230 </RequiredPrefixes>
242 </RequiredPrefixes>
231 </NamingRule>
243 </NamingRule>
232 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
244 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
233 <RequiredPrefixes>
245 <RequiredPrefixes>
234 <String>_</String>
246 <String>_</String>
235 </RequiredPrefixes>
247 </RequiredPrefixes>
236 </NamingRule>
248 </NamingRule>
237 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
249 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
238 <RequiredPrefixes>
250 <RequiredPrefixes>
239 <String>m_</String>
251 <String>m_</String>
240 </RequiredPrefixes>
252 </RequiredPrefixes>
241 </NamingRule>
253 </NamingRule>
242 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
254 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
243 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
255 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
244 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
256 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
245 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
257 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
246 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
258 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
247 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
259 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
248 <RequiredPrefixes>
260 <RequiredPrefixes>
249 <String>T</String>
261 <String>T</String>
250 </RequiredPrefixes>
262 </RequiredPrefixes>
251 </NamingRule>
263 </NamingRule>
252 </Rules>
264 </Rules>
253 </NameConventionPolicy>
265 </NameConventionPolicy>
254 </Policies>
266 </Policies>
255 </Properties>
267 </Properties>
256 </MonoDevelop>
268 </MonoDevelop>
257 </ProjectExtensions>
269 </ProjectExtensions>
258 <ItemGroup>
270 <ItemGroup>
259 <Folder Include="Components\" />
271 <Folder Include="Components\" />
272 <Folder Include="Automaton\RegularExpressions\" />
273 <Folder Include="Formats\" />
274 <Folder Include="Formats\JSON\" />
260 </ItemGroup>
275 </ItemGroup>
261 </Project> No newline at end of file
276 </Project>
@@ -1,299 +1,289
1 using System.Threading;
1 using System.Threading;
2 using System;
2 using System;
3 using Implab.Diagnostics;
3 using Implab.Diagnostics;
4 using System.Collections.Generic;
4 using System.Collections.Generic;
5
5
6
7 #if NET_4_5
8 using System.Threading.Tasks;
9 #endif
10
11 namespace Implab {
6 namespace Implab {
12 public static class PromiseExtensions {
7 public static class PromiseExtensions {
13 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
8 public static IPromise<T> DispatchToCurrentContext<T>(this IPromise<T> that) {
14 Safe.ArgumentNotNull(that, "that");
9 Safe.ArgumentNotNull(that, "that");
15 var context = SynchronizationContext.Current;
10 var context = SynchronizationContext.Current;
16 if (context == null)
11 if (context == null)
17 return that;
12 return that;
18
13
19 var p = new SyncContextPromise<T>(context);
14 var p = new SyncContextPromise<T>(context);
20 p.On(that.Cancel, PromiseEventType.Cancelled);
15 p.CancellationRequested(that.Cancel);
21
16
22 that.On(
17 that.On(
23 p.Resolve,
18 p.Resolve,
24 p.Reject,
19 p.Reject,
25 p.Cancel
20 p.CancelOperation
26 );
21 );
27 return p;
22 return p;
28 }
23 }
29
24
30 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
25 public static IPromise<T> DispatchToContext<T>(this IPromise<T> that, SynchronizationContext context) {
31 Safe.ArgumentNotNull(that, "that");
26 Safe.ArgumentNotNull(that, "that");
32 Safe.ArgumentNotNull(context, "context");
27 Safe.ArgumentNotNull(context, "context");
33
28
34 var p = new SyncContextPromise<T>(context);
29 var p = new SyncContextPromise<T>(context);
35 p.On(that.Cancel, PromiseEventType.Cancelled);
30 p.CancellationRequested(that.Cancel);
36
37
31
38 that.On(
32 that.On(
39 p.Resolve,
33 p.Resolve,
40 p.Reject,
34 p.Reject,
41 p.Cancel
35 p.CancelOperation
42 );
36 );
43 return p;
37 return p;
44 }
38 }
45
39
46 /// <summary>
40 /// <summary>
47 /// Ensures the dispatched.
41 /// Ensures the dispatched.
48 /// </summary>
42 /// </summary>
49 /// <returns>The dispatched.</returns>
43 /// <returns>The dispatched.</returns>
50 /// <param name="that">That.</param>
44 /// <param name="that">That.</param>
51 /// <param name="head">Head.</param>
45 /// <param name="head">Head.</param>
52 /// <param name="cleanup">Cleanup.</param>
46 /// <param name="cleanup">Cleanup.</param>
53 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
47 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
54 /// <typeparam name="T">The 2nd type parameter.</typeparam>
48 /// <typeparam name="T">The 2nd type parameter.</typeparam>
55 public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{
49 public static TPromise EnsureDispatched<TPromise,T>(this TPromise that, IPromise<T> head, Action<T> cleanup) where TPromise : IPromise{
56 Safe.ArgumentNotNull(that, "that");
50 Safe.ArgumentNotNull(that, "that");
57 Safe.ArgumentNotNull(head, "head");
51 Safe.ArgumentNotNull(head, "head");
58
52
59 that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
53 that.On(() => head.On(cleanup), PromiseEventType.Cancelled);
60
54
61 return that;
55 return that;
62 }
56 }
63
57
64 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
58 public static AsyncCallback AsyncCallback<T>(this Promise<T> that, Func<IAsyncResult,T> callback) {
65 Safe.ArgumentNotNull(that, "that");
59 Safe.ArgumentNotNull(that, "that");
66 Safe.ArgumentNotNull(callback, "callback");
60 Safe.ArgumentNotNull(callback, "callback");
67 var op = TraceContext.Instance.CurrentOperation;
61 var op = TraceContext.Instance.CurrentOperation;
68 return ar => {
62 return ar => {
69 TraceContext.Instance.EnterLogicalOperation(op,false);
63 TraceContext.Instance.EnterLogicalOperation(op,false);
70 try {
64 try {
71 that.Resolve(callback(ar));
65 that.Resolve(callback(ar));
72 } catch (Exception err) {
66 } catch (Exception err) {
73 that.Reject(err);
67 that.Reject(err);
74 } finally {
68 } finally {
75 TraceContext.Instance.Leave();
69 TraceContext.Instance.Leave();
76 }
70 }
77 };
71 };
78 }
72 }
79
73
80 static void CancelCallback(object cookie) {
74 static void CancelByTimeoutCallback(object cookie) {
81 ((ICancellable)cookie).Cancel();
75 ((ICancellable)cookie).Cancel(new TimeoutException());
82 }
76 }
83
77
84 /// <summary>
78 /// <summary>
85 /// Cancells promise after the specified timeout is elapsed.
79 /// Cancells promise after the specified timeout is elapsed.
86 /// </summary>
80 /// </summary>
87 /// <param name="that">The promise to cancel on timeout.</param>
81 /// <param name="that">The promise to cancel on timeout.</param>
88 /// <param name="milliseconds">The timeout in milliseconds.</param>
82 /// <param name="milliseconds">The timeout in milliseconds.</param>
89 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
83 /// <typeparam name="TPromise">The 1st type parameter.</typeparam>
90 public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise {
84 public static TPromise Timeout<TPromise>(this TPromise that, int milliseconds) where TPromise : IPromise {
91 Safe.ArgumentNotNull(that, "that");
85 Safe.ArgumentNotNull(that, "that");
92 var timer = new Timer(CancelCallback, that, milliseconds, -1);
86 var timer = new Timer(CancelByTimeoutCallback, that, milliseconds, -1);
93 that.On(timer.Dispose, PromiseEventType.All);
87 that.On(timer.Dispose, PromiseEventType.All);
94 return that;
88 return that;
95 }
89 }
96
90
97 public static IPromise Bundle(this ICollection<IPromise> that) {
91 public static IPromise Bundle(this ICollection<IPromise> that) {
98 Safe.ArgumentNotNull(that, "that");
92 Safe.ArgumentNotNull(that, "that");
99
93
100 int count = that.Count;
94 int count = that.Count;
101 int errors = 0;
95 int errors = 0;
102 var medium = new Promise();
96 var medium = new Promise();
103
97
104 if (count == 0) {
98 if (count == 0) {
105 medium.Resolve();
99 medium.Resolve();
106 return medium;
100 return medium;
107 }
101 }
108
102
109 medium.On(() => {
103 medium.On(() => {
110 foreach(var p2 in that)
104 foreach(var p2 in that)
111 p2.Cancel();
105 p2.Cancel();
112 }, PromiseEventType.ErrorOrCancel);
106 }, PromiseEventType.ErrorOrCancel);
113
107
114 foreach (var p in that)
108 foreach (var p in that)
115 p.On(
109 p.On(
116 () => {
110 () => {
117 if (Interlocked.Decrement(ref count) == 0)
111 if (Interlocked.Decrement(ref count) == 0)
118 medium.Resolve();
112 medium.Resolve();
119 },
113 },
120 error => {
114 error => {
121 if (Interlocked.Increment(ref errors) == 1)
115 if (Interlocked.Increment(ref errors) == 1)
122 medium.Reject(
116 medium.Reject(
123 new Exception("The dependency promise is failed", error)
117 new Exception("The dependency promise is failed", error)
124 );
118 );
125 },
119 },
126 reason => {
120 reason => {
127 if (Interlocked.Increment(ref errors) == 1)
121 if (Interlocked.Increment(ref errors) == 1)
128 medium.Cancel(
122 medium.Cancel(
129 new Exception("The dependency promise is cancelled")
123 new Exception("The dependency promise is cancelled")
130 );
124 );
131 }
125 }
132 );
126 );
133
127
134 return medium;
128 return medium;
135 }
129 }
136
130
137 public static IPromise<T[]> Bundle<T>(this ICollection<IPromise<T>> that) {
131 public static IPromise<T[]> Bundle<T>(this ICollection<IPromise<T>> that) {
138 Safe.ArgumentNotNull(that, "that");
132 Safe.ArgumentNotNull(that, "that");
139
133
140 int count = that.Count;
134 int count = that.Count;
141 int errors = 0;
135 int errors = 0;
142 var medium = new Promise<T[]>();
136 var medium = new Promise<T[]>();
143 var results = new T[that.Count];
137 var results = new T[that.Count];
144
138
145 medium.On(() => {
139 medium.On(() => {
146 foreach(var p2 in that)
140 foreach(var p2 in that)
147 p2.Cancel();
141 p2.Cancel();
148 }, PromiseEventType.ErrorOrCancel);
142 }, PromiseEventType.ErrorOrCancel);
149
143
150 int i = 0;
144 int i = 0;
151 foreach (var p in that) {
145 foreach (var p in that) {
152 var idx = i;
146 var idx = i;
153 p.On(
147 p.On(
154 x => {
148 x => {
155 results[idx] = x;
149 results[idx] = x;
156 if (Interlocked.Decrement(ref count) == 0)
150 if (Interlocked.Decrement(ref count) == 0)
157 medium.Resolve(results);
151 medium.Resolve(results);
158 },
152 },
159 error => {
153 error => {
160 if (Interlocked.Increment(ref errors) == 1)
154 if (Interlocked.Increment(ref errors) == 1)
161 medium.Reject(
155 medium.Reject(
162 new Exception("The dependency promise is failed", error)
156 new Exception("The dependency promise is failed", error)
163 );
157 );
164 },
158 },
165 reason => {
159 reason => {
166 if (Interlocked.Increment(ref errors) == 1)
160 if (Interlocked.Increment(ref errors) == 1)
167 medium.Cancel(
161 medium.Cancel(
168 new Exception("The dependency promise is cancelled", reason)
162 new Exception("The dependency promise is cancelled", reason)
169 );
163 );
170 }
164 }
171 );
165 );
172 i++;
166 i++;
173 }
167 }
174
168
175 return medium;
169 return medium;
176 }
170 }
177
171
178 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
172 public static IPromise Then(this IPromise that, Action success, Action<Exception> error, Action<Exception> cancel) {
179 Safe.ArgumentNotNull(that, "that");
173 Safe.ArgumentNotNull(that, "that");
180
174
181 var d = new ActionTask(success, error, cancel, false);
175 var d = new ActionTask(success, error, cancel, false);
182 that.On(d.Resolve, d.Reject, d.CancelOperation);
176 that.On(d.Resolve, d.Reject, d.CancelOperation);
183 if (success != null)
177 d.CancellationRequested(that.Cancel);
184 d.CancellationRequested(that.Cancel);
185 return d;
178 return d;
186 }
179 }
187
180
188 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
181 public static IPromise Then(this IPromise that, Action success, Action<Exception> error) {
189 return Then(that, success, error, null);
182 return Then(that, success, error, null);
190 }
183 }
191
184
192 public static IPromise Then(this IPromise that, Action success) {
185 public static IPromise Then(this IPromise that, Action success) {
193 return Then(that, success, null, null);
186 return Then(that, success, null, null);
194 }
187 }
195
188
196 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
189 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error, Func<Exception, T> cancel) {
197 Safe.ArgumentNotNull(that, "that");
190 Safe.ArgumentNotNull(that, "that");
198
191
199 var d = new FuncTask<T>(success, error, cancel, false);
192 var d = new FuncTask<T>(success, error, cancel, false);
200 that.On(d.Resolve, d.Reject, d.CancelOperation);
193 that.On(d.Resolve, d.Reject, d.CancelOperation);
201 if (success != null)
194 d.CancellationRequested(that.Cancel);
202 d.CancellationRequested(that.Cancel);
203 return d;
195 return d;
204 }
196 }
205
197
206 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error) {
198 public static IPromise<T> Then<T>(this IPromise that, Func<T> success, Func<Exception, T> error) {
207 return Then(that, success, error, null);
199 return Then(that, success, error, null);
208 }
200 }
209
201
210 public static IPromise<T> Then<T>(this IPromise that, Func<T> success) {
202 public static IPromise<T> Then<T>(this IPromise that, Func<T> success) {
211 return Then(that, success, null, null);
203 return Then(that, success, null, null);
212 }
204 }
213
205
214 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) {
206 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error, Func<Exception, T2> cancel) {
215 Safe.ArgumentNotNull(that, "that");
207 Safe.ArgumentNotNull(that, "that");
216 var d = new FuncTask<T,T2>(success, error, cancel, false);
208 var d = new FuncTask<T,T2>(success, error, cancel, false);
217 that.On(d.Resolve, d.Reject, d.CancelOperation);
209 that.On(d.Resolve, d.Reject, d.CancelOperation);
218 if (success != null)
210 d.CancellationRequested(that.Cancel);
219 d.CancellationRequested(that.Cancel);
220 return d;
211 return d;
221 }
212 }
222
213
223 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
214 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success, Func<Exception, T2> error) {
224 return Then(that, success, error, null);
215 return Then(that, success, error, null);
225 }
216 }
226
217
227 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) {
218 public static IPromise<T2> Then<T, T2>(this IPromise<T> that, Func<T, T2> success) {
228 return Then(that, success, null, null);
219 return Then(that, success, null, null);
229 }
220 }
230
221
231 #region chain traits
222 #region chain traits
232 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error, Func<Exception,IPromise> cancel) {
223 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error, Func<Exception,IPromise> cancel) {
233 Safe.ArgumentNotNull(that, "that");
224 Safe.ArgumentNotNull(that, "that");
234
225
235 var d = new ActionChainTask(success, error, cancel, false);
226 var d = new ActionChainTask(success, error, cancel, false);
236 that.On(d.Resolve, d.Reject, d.CancelOperation);
227 that.On(d.Resolve, d.Reject, d.CancelOperation);
237 if (success != null)
228 d.CancellationRequested(that.Cancel);
238 d.CancellationRequested(that.Cancel);
239 return d;
229 return d;
240 }
230 }
241
231
242 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) {
232 public static IPromise Chain(this IPromise that, Func<IPromise> success, Func<Exception,IPromise> error) {
243 return Chain(that, success, error, null);
233 return Chain(that, success, error, null);
244 }
234 }
245
235
246 public static IPromise Chain(this IPromise that, Func<IPromise> success) {
236 public static IPromise Chain(this IPromise that, Func<IPromise> success) {
247 return Chain(that, success, null, null);
237 return Chain(that, success, null, null);
248 }
238 }
249
239
250 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) {
240 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error, Func<Exception, IPromise<T>> cancel) {
251 Safe.ArgumentNotNull(that, "that");
241 Safe.ArgumentNotNull(that, "that");
252
242
253 var d = new FuncChainTask<T>(success, error, cancel, false);
243 var d = new FuncChainTask<T>(success, error, cancel, false);
254 that.On(d.Resolve, d.Reject, d.CancelOperation);
244 that.On(d.Resolve, d.Reject, d.CancelOperation);
255 if (success != null)
245 if (success != null)
256 d.CancellationRequested(that.Cancel);
246 d.CancellationRequested(that.Cancel);
257 return d;
247 return d;
258 }
248 }
259
249
260 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) {
250 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success, Func<Exception, IPromise<T>> error) {
261 return Chain(that, success, error, null);
251 return Chain(that, success, error, null);
262 }
252 }
263
253
264 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) {
254 public static IPromise<T> Chain<T>(this IPromise that, Func<IPromise<T>> success) {
265 return Chain(that, success, null, null);
255 return Chain(that, success, null, null);
266 }
256 }
267
257
268 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
258 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error, Func<Exception, IPromise<T2>> cancel) {
269 Safe.ArgumentNotNull(that, "that");
259 Safe.ArgumentNotNull(that, "that");
270 var d = new FuncChainTask<T,T2>(success, error, cancel, false);
260 var d = new FuncChainTask<T,T2>(success, error, cancel, false);
271 that.On(d.Resolve, d.Reject, d.CancelOperation);
261 that.On(d.Resolve, d.Reject, d.CancelOperation);
272 if (success != null)
262 if (success != null)
273 d.CancellationRequested(that.Cancel);
263 d.CancellationRequested(that.Cancel);
274 return d;
264 return d;
275 }
265 }
276
266
277 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) {
267 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success, Func<Exception, IPromise<T2>> error) {
278 return Chain(that, success, error, null);
268 return Chain(that, success, error, null);
279 }
269 }
280
270
281 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) {
271 public static IPromise<T2> Chain<T, T2>(this IPromise<T> that, Func<T, IPromise<T2>> success) {
282 return Chain(that, success, null, null);
272 return Chain(that, success, null, null);
283 }
273 }
284
274
285 #endregion
275 #endregion
286
276
287
277
288 #if NET_4_5
278 #if NET_4_5
289
279
290 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
280 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
291 Safe.ArgumentNotNull(that, "that");
281 Safe.ArgumentNotNull(that, "that");
292
282
293 return new PromiseAwaiter<T>(that);
283 return new PromiseAwaiter<T>(that);
294 }
284 }
295
285
296 #endif
286 #endif
297 }
287 }
298 }
288 }
299
289
@@ -1,123 +1,128
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
7
8 namespace Implab
8 namespace Implab
9 {
9 {
10 public static class Safe
10 public static class Safe
11 {
11 {
12 public static void ArgumentAssert(bool condition, string paramName) {
12 public static void ArgumentAssert(bool condition, string paramName) {
13 if (!condition)
13 if (!condition)
14 throw new ArgumentException("The parameter is invalid", paramName);
14 throw new ArgumentException("The parameter is invalid", paramName);
15 }
15 }
16
16
17 public static void ArgumentMatch(string value, string paramName, Regex rx) {
17 public static void ArgumentMatch(string value, string paramName, Regex rx) {
18 if (rx == null)
18 if (rx == null)
19 throw new ArgumentNullException("rx");
19 throw new ArgumentNullException("rx");
20 if (!rx.IsMatch(value))
20 if (!rx.IsMatch(value))
21 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
21 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
22 }
22 }
23
23
24 public static void ArgumentNotEmpty(string value, string paramName) {
24 public static void ArgumentNotEmpty(string value, string paramName) {
25 if (String.IsNullOrEmpty(value))
25 if (String.IsNullOrEmpty(value))
26 throw new ArgumentException("The parameter can't be empty", paramName);
26 throw new ArgumentException("The parameter can't be empty", paramName);
27 }
27 }
28
28
29 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
29 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
30 if (value == null || value.Length == 0)
30 if (value == null || value.Length == 0)
31 throw new ArgumentException("The array must be not emty", paramName);
31 throw new ArgumentException("The array must be not emty", paramName);
32 }
32 }
33
33
34 public static void ArgumentNotNull(object value, string paramName) {
34 public static void ArgumentNotNull(object value, string paramName) {
35 if (value == null)
35 if (value == null)
36 throw new ArgumentNullException(paramName);
36 throw new ArgumentNullException(paramName);
37 }
37 }
38
38
39 public static void ArgumentInRange(int value, int min, int max, string paramName) {
39 public static void ArgumentInRange(int value, int min, int max, string paramName) {
40 if (value < min || value > max)
40 if (value < min || value > max)
41 throw new ArgumentOutOfRangeException(paramName);
41 throw new ArgumentOutOfRangeException(paramName);
42 }
42 }
43
43
44 public static void ArgumentOfType(object value, Type type, string paramName) {
45 if (!type.IsInstanceOfType(value))
46 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
47 }
48
44 public static void Dispose(params IDisposable[] objects) {
49 public static void Dispose(params IDisposable[] objects) {
45 foreach (var d in objects)
50 foreach (var d in objects)
46 if (d != null)
51 if (d != null)
47 d.Dispose();
52 d.Dispose();
48 }
53 }
49
54
50 public static void Dispose(params object[] objects) {
55 public static void Dispose(params object[] objects) {
51 foreach (var obj in objects) {
56 foreach (var obj in objects) {
52 var d = obj as IDisposable;
57 var d = obj as IDisposable;
53 if (d != null)
58 if (d != null)
54 d.Dispose();
59 d.Dispose();
55 }
60 }
56 }
61 }
57
62
58 public static void Dispose(object obj) {
63 public static void Dispose(object obj) {
59 var d = obj as IDisposable;
64 var d = obj as IDisposable;
60 if (d != null)
65 if (d != null)
61 d.Dispose();
66 d.Dispose();
62 }
67 }
63
68
64 [DebuggerStepThrough]
69 [DebuggerStepThrough]
65 public static IPromise<T> WrapPromise<T>(Func<T> action) {
70 public static IPromise<T> WrapPromise<T>(Func<T> action) {
66 ArgumentNotNull(action, "action");
71 ArgumentNotNull(action, "action");
67
72
68 var p = new Promise<T>();
73 var p = new Promise<T>();
69 try {
74 try {
70 p.Resolve(action());
75 p.Resolve(action());
71 } catch (Exception err) {
76 } catch (Exception err) {
72 p.Reject(err);
77 p.Reject(err);
73 }
78 }
74
79
75 return p;
80 return p;
76 }
81 }
77
82
78 [DebuggerStepThrough]
83 [DebuggerStepThrough]
79 public static IPromise WrapPromise(Action action) {
84 public static IPromise WrapPromise(Action action) {
80 ArgumentNotNull(action, "action");
85 ArgumentNotNull(action, "action");
81
86
82 var p = new Promise();
87 var p = new Promise();
83 try {
88 try {
84 action();
89 action();
85 p.Resolve();
90 p.Resolve();
86 } catch (Exception err) {
91 } catch (Exception err) {
87 p.Reject(err);
92 p.Reject(err);
88 }
93 }
89
94
90 return p;
95 return p;
91 }
96 }
92
97
93 [DebuggerStepThrough]
98 [DebuggerStepThrough]
94 public static IPromise InvokePromise(Func<IPromise> action) {
99 public static IPromise InvokePromise(Func<IPromise> action) {
95 ArgumentNotNull(action, "action");
100 ArgumentNotNull(action, "action");
96
101
97 try {
102 try {
98 var p = action();
103 var p = action();
99 if (p == null) {
104 if (p == null) {
100 var d = new Promise();
105 var d = new Promise();
101 d.Reject(new Exception("The action returned null"));
106 d.Reject(new Exception("The action returned null"));
102 p = d;
107 p = d;
103 }
108 }
104 return p;
109 return p;
105 } catch (Exception err) {
110 } catch (Exception err) {
106 var p = new Promise();
111 var p = new Promise();
107 p.Reject(err);
112 p.Reject(err);
108 return p;
113 return p;
109 }
114 }
110 }
115 }
111
116
112 [DebuggerStepThrough]
117 [DebuggerStepThrough]
113 public static IPromise<T> InvokePromise<T>(Func<IPromise<T>> action) {
118 public static IPromise<T> InvokePromise<T>(Func<IPromise<T>> action) {
114 ArgumentNotNull(action, "action");
119 ArgumentNotNull(action, "action");
115
120
116 try {
121 try {
117 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
122 return action() ?? Promise<T>.FromException(new Exception("The action returned null"));
118 } catch (Exception err) {
123 } catch (Exception err) {
119 return Promise<T>.FromException(err);
124 return Promise<T>.FromException(err);
120 }
125 }
121 }
126 }
122 }
127 }
123 }
128 }
@@ -1,47 +1,53
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>8.0.30703</ProductVersion>
6 <ProductVersion>8.0.30703</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{15DD7123-D504-4627-8B4F-D00C7F04D033}</ProjectGuid>
8 <ProjectGuid>{15DD7123-D504-4627-8B4F-D00C7F04D033}</ProjectGuid>
9 <OutputType>Exe</OutputType>
9 <OutputType>Exe</OutputType>
10 <RootNamespace>MonoPlay</RootNamespace>
10 <RootNamespace>MonoPlay</RootNamespace>
11 <AssemblyName>MonoPlay</AssemblyName>
11 <AssemblyName>MonoPlay</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <ReleaseVersion>0.2</ReleaseVersion>
13 <ReleaseVersion>0.2</ReleaseVersion>
14 </PropertyGroup>
14 </PropertyGroup>
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 <DebugSymbols>true</DebugSymbols>
16 <DebugSymbols>true</DebugSymbols>
17 <DebugType>full</DebugType>
17 <DebugType>full</DebugType>
18 <Optimize>false</Optimize>
18 <Optimize>false</Optimize>
19 <OutputPath>bin\Debug</OutputPath>
19 <OutputPath>bin\Debug</OutputPath>
20 <DefineConstants>DEBUG;TRACE;</DefineConstants>
20 <DefineConstants>DEBUG;TRACE;</DefineConstants>
21 <ErrorReport>prompt</ErrorReport>
21 <ErrorReport>prompt</ErrorReport>
22 <WarningLevel>4</WarningLevel>
22 <WarningLevel>4</WarningLevel>
23 <ConsolePause>false</ConsolePause>
23 <ConsolePause>false</ConsolePause>
24 </PropertyGroup>
24 </PropertyGroup>
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 <DebugType>full</DebugType>
26 <DebugType>full</DebugType>
27 <Optimize>true</Optimize>
27 <Optimize>true</Optimize>
28 <OutputPath>bin\Release</OutputPath>
28 <OutputPath>bin\Release</OutputPath>
29 <ErrorReport>prompt</ErrorReport>
29 <ErrorReport>prompt</ErrorReport>
30 <WarningLevel>4</WarningLevel>
30 <WarningLevel>4</WarningLevel>
31 <ConsolePause>false</ConsolePause>
31 <ConsolePause>false</ConsolePause>
32 </PropertyGroup>
32 </PropertyGroup>
33 <ItemGroup>
33 <ItemGroup>
34 <Reference Include="System" />
34 <Reference Include="System" />
35 <Reference Include="System.Text.Json">
36 <HintPath>..\packages\System.Text.Json.2.0.0.11\lib\net40\System.Text.Json.dll</HintPath>
37 </Reference>
35 </ItemGroup>
38 </ItemGroup>
36 <ItemGroup>
39 <ItemGroup>
37 <Compile Include="Program.cs" />
40 <Compile Include="Program.cs" />
38 <Compile Include="Properties\AssemblyInfo.cs" />
41 <Compile Include="Properties\AssemblyInfo.cs" />
39 </ItemGroup>
42 </ItemGroup>
40 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
43 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
41 <ItemGroup>
44 <ItemGroup>
42 <ProjectReference Include="..\Implab\Implab.csproj">
45 <ProjectReference Include="..\Implab\Implab.csproj">
43 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
46 <Project>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</Project>
44 <Name>Implab</Name>
47 <Name>Implab</Name>
45 </ProjectReference>
48 </ProjectReference>
46 </ItemGroup>
49 </ItemGroup>
50 <ItemGroup>
51 <None Include="packages.config" />
52 </ItemGroup>
47 </Project> No newline at end of file
53 </Project>
@@ -1,37 +1,45
1 using System;
1 using System;
2 using Implab;
2 using Implab;
3 using System.Threading.Tasks;
3 using System.Threading.Tasks;
4 using Implab.Formats.JSON;
5 using System.IO;
6 using System.Text.Json;
4
7
5 namespace MonoPlay {
8 namespace MonoPlay {
6 class MainClass {
9 class MainClass {
7
10
8
11
9 public static void Main(string[] args) {
12 public static void Main(string[] args) {
10 if (args == null)
13 if (args == null)
11 throw new ArgumentNullException("args");
14 throw new ArgumentNullException("args");
12
15 int t1, t2;
13 var t1 = Environment.TickCount;
14
15 DoWork().GetAwaiter().GetResult();
16
16
17 var t2 = Environment.TickCount;
17 for (int i = 0; i < 2; i++) {
18 Console.WriteLine("done: {0} ms, {1:.00} Mb, {2} GC", t2 - t1, GC.GetTotalMemory(false) / (1024*1024), GC.CollectionCount(0) );
18 t1 = Environment.TickCount;
19 int elements =0;
20 using (var reader = new JSONParser(File.OpenText("/home/sergey/temp/citylots.json"))) {
21 while (reader.Read())
22 elements++;
23 }
19
24
20 }
25 t2 = Environment.TickCount;
26 Console.WriteLine("attempt {0} done: {1} ms, {2:.00} Mb, {3} GC, Elements: {4}",i+1, t2 - t1, GC.GetTotalMemory(false) / (1024*1024), GC.CollectionCount(0), elements );
27 }
21
28
22 static IPromise<int> DoItem(int x) {
29 Console.WriteLine("Syste.Text.Json");
23 //return Promise<int>.FromResult(x + 1);
30 var paraser = new JsonParser();
24 var p = new Promise<int>();
31 for (int i = 0; i < 2; i++) {
25 p.Resolve(x+1);
32 t1 = Environment.TickCount;
26 return p;
33 using (var reader = File.OpenText("/home/sergey/temp/citylots.json")) {
27 }
34 paraser.Parse(reader);
35 }
28
36
29 static async Task<int> DoWork() {
37 t2 = Environment.TickCount;
30 var c = 0;
38 Console.WriteLine("attempt {0} done: {1} ms, {2:.00} Mb, {3} GC, ",i+1, t2 - t1, GC.GetTotalMemory(false) / (1024*1024), GC.CollectionCount(0));
31 for (int i = 0; i < 10000000; i++)
39 }
32 c = await DoItem(c);
40
33 return c;
41
34 }
42 }
35
43
36 }
44 }
37 }
45 }
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now