##// END OF EJS Templates
Fixed promise rejection when there is not specified error handler in the reaction....
cin -
r295:28af686e24f7 default
parent child
Show More
@@ -1,29 +1,28
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 </PropertyGroup>
6
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
9 </PropertyGroup>
10
11 <PropertyGroup>
12 <IsPackable>false</IsPackable>
13 </PropertyGroup>
2 <PropertyGroup>
3 <TargetFramework>net5.0</TargetFramework>
4
5 <IsPackable>false</IsPackable>
6 </PropertyGroup>
14 7
15 8 <ItemGroup>
16 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
9 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
10 <PackageReference Include="xunit" Version="2.4.1" />
11 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
12 <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13 <PrivateAssets>all</PrivateAssets>
14 </PackageReference>
15 <PackageReference Include="coverlet.collector" Version="1.3.0">
16 <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17 <PrivateAssets>all</PrivateAssets>
18 </PackageReference>
17 19 <PackageReference Include="System.Reactive" Version="4.0.0" />
18 <PackageReference Include="xunit" Version="2.3.1" />
19 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
20 20 <ProjectReference Include="../Implab/Implab.csproj"/>
21 21 <ProjectReference Include="../Implab.ServiceHost/Implab.ServiceHost.csproj"/>
22 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
23 22 </ItemGroup>
24 23
25 24 <ItemGroup>
26 25 <None Include="data/**/*.*" CopyToOutputDirectory="PreserveNewest" />
27 26 </ItemGroup>
28 27
29 </Project>
28 </Project> No newline at end of file
@@ -1,36 +1,36
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 2
3 3 <PropertyGroup>
4 4 <Authors>Sergey Smirnov</Authors>
5 5 <Title>Implab.ServiceHost</Title>
6 6 <Description>The configurable application host.
7 7 Provides simple and flexible Xml configuration for UnityContainer.
8 8 </Description>
9 <Copyright>2012-2018 Sergey Smirnov</Copyright>
10 <Version>1.0.3</Version>
11 <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl>
12 <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl>
13 <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl>
9 <Copyright>2012-2021 Sergey Smirnov</Copyright>
10 <Version>1.0.4</Version>
11 <PackageLicenseUrl>https://code.implab.org/implab/ImplabNet/files/default/Implab/license.txt</PackageLicenseUrl>
12 <PackageProjectUrl>https://code.implab.org/implab/ImplabNet/</PackageProjectUrl>
13 <RepositoryUrl>https://code.implab.org/implab/ImplabNet/</RepositoryUrl>
14 14 <RepositoryType>mercurial</RepositoryType>
15 15 <PackageTags>Implab;Xml configuration;IoC;Unity container</PackageTags>
16 16 </PropertyGroup>
17 17
18 18
19 19 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
20 20 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
21 21 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
22 22 </PropertyGroup>
23 23
24 24 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
25 25 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
26 26 </PropertyGroup>
27 27
28 28 <ItemGroup>
29 29 <PackageReference Include="Unity" Version="5.8.6" />
30 30 </ItemGroup>
31 31
32 32 <ItemGroup>
33 33 <ProjectReference Include="..\Implab\Implab.csproj" />
34 34 </ItemGroup>
35 35
36 36 </Project>
@@ -1,48 +1,47
1 1 using System;
2 2 using System.Xml.Serialization;
3 3 using Unity.Lifetime;
4 using Unity.Registration;
5 4
6 5 namespace Implab.ServiceHost.Unity
7 6 {
8 7 /// <summary>
9 8 /// Базовая ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈ ΠΎ рСгистрации Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅: Ρ‚ΠΈΠΏ, имя ΠΈ врСмя ΠΆΠΈΠ·Π½ΠΈ
10 9 /// </summary>
11 10 public abstract class AbstractRegistration : AbstractContainerItem, IRegistration {
12 11
13 12 /// <summary>
14 13 /// An optional name for a registration in the container
15 14 /// </summary>
16 15 [XmlAttribute("name")]
17 16 public string Name {
18 17 get; set;
19 18 }
20 19
21 [XmlElement("signleton", typeof(SingletonLifetimeElement))]
20 [XmlElement("singleton", typeof(SingletonLifetimeElement))]
22 21 [XmlElement("context", typeof(ContextLifetimeElement))]
23 22 [XmlElement("container", typeof(ContainerLifetimeElement))]
24 23 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
25 24 public LifetimeElement Lifetime {get; set;}
26 25
27 26 /// <summary>
28 27 /// A type specification for the service registration,
29 28 /// </summary>
30 29 [XmlAttribute("type")]
31 30 public string RegistrationType { get; set; }
32 31
33 32 public virtual LifetimeManager GetLifetime(ContainerBuilder builder) {
34 33 return Lifetime?.GetLifetime(builder);
35 34 }
36 35
37 36 public virtual Type GetRegistrationType(Func<string,Type> resolver) {
38 37 return resolver(RegistrationType);
39 38 }
40 39
41 40 public virtual Type GetRegistrationType(ContainerBuilder builder) {
42 41 return builder.ResolveType(RegistrationType);
43 42 }
44 43
45 44
46 45
47 46 }
48 47 } No newline at end of file
@@ -1,70 +1,67
1 1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Reflection;
5 2 using System.Xml;
6 3 using System.Xml.Serialization;
7 4 using Implab.Components;
8 5
9 6 namespace Implab.ServiceHost.Unity {
10 7 public class ContainerConfigurationSchema {
11 8
12 9 public static ContainerConfigurationSchema Default { get; private set; } = CreateDefault();
13 10
14 11 readonly LazyAndWeak<XmlSerializer> m_seralizer;
15 12
16 13 readonly XmlAttributeOverrides m_overrides = new XmlAttributeOverrides();
17 14
18 15 readonly XmlAttributes m_containerItems = new XmlAttributes();
19 16
20 17 public XmlSerializer Serializer {
21 18 get {
22 19 return m_seralizer.Value;
23 20 }
24 21 }
25 22
26 23 public ContainerConfigurationSchema() {
27 24 m_overrides.Add(typeof(ContainerElement), nameof(ContainerElement.Items), m_containerItems);
28 25
29 26 m_seralizer = new LazyAndWeak<XmlSerializer>(() => new XmlSerializer(typeof(ContainerElement), m_overrides));
30 27 }
31 28
32 29 public void RegisterContainerElement(Type type, string name) {
33 30 Safe.ArgumentNotNull(type, nameof(type));
34 31 Safe.ArgumentNotEmpty(name, nameof(name));
35 32
36 33 if(!type.IsSubclassOf(typeof(AbstractContainerItem)))
37 34 throw new Exception($"RegisterContainerElement '{name}': {type} must be subclass of {typeof(AbstractContainerItem)}");
38 35
39 36 m_containerItems.XmlElements.Add(
40 37 new XmlElementAttribute(name, type)
41 38 );
42 39 }
43 40
44 41 public void RegisterContainerElement<T>(string name) where T : AbstractContainerItem {
45 42 RegisterContainerElement(typeof(T), name);
46 43 }
47 44
48 45 public ContainerElement LoadConfig(string uri) {
49 46 using (var reader = XmlReader.Create(uri)) {
50 47 return (ContainerElement)Serializer.Deserialize(reader);
51 48 }
52 49 }
53 50
54 51 static ContainerConfigurationSchema CreateDefault() {
55 52 var schema = new ContainerConfigurationSchema();
56 53
57 54 schema.RegisterContainerElement<RegisterElement>("register");
58 55 schema.RegisterContainerElement<FactoryElement>("factory");
59 56 schema.RegisterContainerElement<SerializedElement>("serialized");
60 57 schema.RegisterContainerElement<ValueElement>("value");
61 58 schema.RegisterContainerElement<IncludeElement>("include");
62 59 schema.RegisterContainerElement<AssemblyElement>("assembly");
63 60 schema.RegisterContainerElement<NamespaceElement>("namespace");
64 61
65 62 return schema;
66 63 }
67 64
68 65
69 66 }
70 67 } No newline at end of file
@@ -1,17 +1,17
1 1 using System.Xml.Serialization;
2 2
3 3 namespace Implab.ServiceHost.Unity {
4 4 public class ProvidesElement {
5 5 [XmlAttribute("type")]
6 6 public string RegistrationType { get; set; }
7 7
8 8 [XmlAttribute("name")]
9 9 public string RegistrationName { get; set; }
10 10
11 [XmlElement("signleton", typeof(SingletonLifetimeElement))]
11 [XmlElement("singleton", typeof(SingletonLifetimeElement))]
12 12 [XmlElement("context", typeof(ContextLifetimeElement))]
13 13 [XmlElement("container", typeof(ContainerLifetimeElement))]
14 14 [XmlElement("hierarchy", typeof(HierarchicalLifetimeElement))]
15 15 public LifetimeElement Lifetime {get; set;}
16 16 }
17 17 } No newline at end of file
@@ -1,10 +1,9
1 1 using Unity.Lifetime;
2 2
3 namespace Implab.ServiceHost.Unity
4 {
3 namespace Implab.ServiceHost.Unity {
5 4 public class SingletonLifetimeElement : LifetimeElement {
6 5 public override LifetimeManager GetLifetime(ContainerBuilder builder) {
7 6 return new SingletonLifetimeManager();
8 7 }
9 8 }
10 9 } No newline at end of file
@@ -1,24 +1,24
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 <PropertyGroup Condition="'$(OSTYPE)'=='linux'">
3 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
4 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 </PropertyGroup>
2 <PropertyGroup>
3 <TargetFramework>net5.0</TargetFramework>
6 4
7 <PropertyGroup Condition="'$(OSTYPE)'=='windows'">
8 <TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
9 </PropertyGroup>
5 <IsPackable>false</IsPackable>
6 </PropertyGroup>
10 7
11 <PropertyGroup>
12 <IsPackable>false</IsPackable>
13 </PropertyGroup>
8 <ItemGroup>
9 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
10 <PackageReference Include="xunit" Version="2.4.1" />
11 <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
12 <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13 <PrivateAssets>all</PrivateAssets>
14 </PackageReference>
15 <PackageReference Include="coverlet.collector" Version="1.3.0">
16 <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17 <PrivateAssets>all</PrivateAssets>
18 </PackageReference>
14 19
15 <ItemGroup>
16 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0-preview-20180109-01" />
17 <PackageReference Include="System.Reactive" Version="4.0.0" />
18 <PackageReference Include="xunit" Version="2.3.1" />
19 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
20 <ProjectReference Include="../Implab/Implab.csproj"/>
21 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
22 </ItemGroup>
23
20 <PackageReference Include="System.Reactive" Version="4.0.0" />
21 <ProjectReference Include="../Implab/Implab.csproj" />
22 </ItemGroup>
23
24 24 </Project>
@@ -1,26 +1,26
1 1 <Project Sdk="Microsoft.NET.Sdk">
2 2
3 3 <PropertyGroup>
4 4 <Authors>Sergey Smirnov</Authors>
5 5 <Title>Implab library</Title>
6 6 <Description>Provides some helper clesses like XML serialization helpers, JSON XML reader,
7 7 JSON pull-parser, ECMA-style promises, lightweight synchonization routines Signal
8 8 and SharedLock, Trace helpers on top of System.Diagnostics, ObjectPool etc.
9 9 </Description>
10 <Copyright>2012-2018 Sergey Smirnov</Copyright>
11 <Version>3.0.14</Version>
10 <Copyright>2012-2021 Sergey Smirnov</Copyright>
11 <Version>3.0.16</Version>
12 12 <PackageLicenseUrl>https://bitbucket.org/wozard/implabnet/src/v3/Implab/license.txt</PackageLicenseUrl>
13 13 <PackageProjectUrl>https://bitbucket.org/wozard/implabnet</PackageProjectUrl>
14 14 <RepositoryUrl>https://bitbucket.org/wozard/implabnet</RepositoryUrl>
15 15 <RepositoryType>mercurial</RepositoryType>
16 16 <PackageTags>IMPLAB;Json pull-parser;Json Xml;async;diagnostics;serialization;</PackageTags>
17 17 <TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
18 18 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
19 19 <DefineConstants Condition="'$(TargetFramework)'=='net46'">NETFX_TRACE_BUG;$(DefineConstants)</DefineConstants>
20 20 </PropertyGroup>
21 21
22 22 <ItemGroup>
23 <EmbeddedResource Include="src\Xml\json.xsl"/>
23 <EmbeddedResource LogicalName="Implab.Xml.json.xsl" Include="src\Xml\json.xsl"/>
24 24 </ItemGroup>
25 25
26 26 </Project>
@@ -1,130 +1,128
1 1 using System;
2 2 using Implab.Parallels;
3 3 using System.Threading;
4 using System.Reflection;
5 using System.Diagnostics;
6 4
7 5 namespace Implab {
8 6 /// <summary>
9 7 /// Abstract class for creation of custom one-shot thread safe events.
10 8 /// </summary>
11 9 /// <remarks>
12 10 /// <para>
13 11 /// An event is something that should happen in the future and the
14 12 /// triggering of the event causes execution of some pending actions
15 13 /// which are formely event handlers. One-shot events occur only once
16 14 /// and any handler added after the event is triggered should run
17 15 /// without a delay.
18 16 /// </para>
19 17 /// <para>
20 18 /// The lifecycle of the one-shot event is tipically consists of following
21 19 /// phases.
22 20 /// <list>
23 21 /// <description>Pending state. This is the initial state of the event. Any
24 22 /// handler added to the event will be queued for the future execution.
25 23 /// </description>
26 24 /// <description>Transitional state. This is intermediate state between pending
27 25 /// and fulfilled states, during this state internal initialization and storing
28 26 /// of the result occurs.
29 27 /// </description>
30 28 /// <description>Fulfilled state. The event contains the result, all queued
31 29 /// handlers are signalled to run and newly added handlers are executed
32 30 /// immediatelly.
33 31 /// </description>
34 32 /// </list>
35 33 /// </para>
36 34 /// </remarks>
37 35 public abstract class AbstractEvent<THandler> where THandler : class {
38 36 const int PendingState = 0;
39 37
40 38 const int TransitionalState = 1;
41 39
42 40 const int ResolvedState = 2;
43 41
44 42 volatile int m_state;
45 43
46 44 THandler m_handler;
47 45 SimpleAsyncQueue<THandler> m_extraHandlers;
48 46
49 47 public bool IsResolved {
50 48 get {
51 49 return m_state > TransitionalState;
52 50 }
53 51 }
54 52
55 53 #region state managment
56 54 protected bool BeginTransit() {
57 55 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
58 56 }
59 57
60 58 protected void CompleteTransit() {
61 59 #if DEBUG
62 60 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
63 61 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
64 62 #else
65 63 m_state = ResolvedState;
66 64 #endif
67 65 Signal();
68 66 }
69 67
70 68 protected void WaitTransition() {
71 69 if (m_state == TransitionalState) {
72 70 SpinWait spin = new SpinWait();
73 71 do {
74 72 spin.SpinOnce();
75 73 } while (m_state == TransitionalState);
76 74 }
77 75 }
78 76
79 77
80 78 protected abstract void SignalHandler(THandler handler);
81 79
82 80 void Signal() {
83 81 THandler handler;
84 82 while (TryDequeueHandler(out handler))
85 83 SignalHandler(handler);
86 84 }
87 85
88 86 #endregion
89 87
90 88 #region handlers managment
91 89
92 90 protected void AddHandler(THandler handler) {
93 91
94 92 if (IsResolved) {
95 93 // the promise is in the resolved state, just invoke the handler
96 94 SignalHandler(handler);
97 95 } else {
98 96 EnqueueHandler(handler);
99 97
100 98 if (IsResolved && TryDequeueHandler(out handler))
101 99 // if the promise have been resolved while we was adding the handler to the queue
102 100 // we can't guarantee that someone is still processing it
103 101 // therefore we need to fetch a handler from the queue and execute it
104 102 // note that fetched handler may be not the one that we have added
105 103 // even we can fetch no handlers at all :)
106 104 SignalHandler(handler);
107 105 }
108 106
109 107 }
110 108
111 109 void EnqueueHandler(THandler handler) {
112 110 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
113 111 if (m_extraHandlers == null)
114 112 // compare-exchange will protect from loosing already created queue
115 113 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
116 114 m_extraHandlers.Enqueue(handler);
117 115 }
118 116 }
119 117
120 118 bool TryDequeueHandler(out THandler handler) {
121 119 handler = Interlocked.Exchange(ref m_handler, null);
122 120 if (handler != null)
123 121 return true;
124 122 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
125 123 }
126 124
127 125 #endregion
128 126 }
129 127 }
130 128
@@ -1,34 +1,30
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
1 using System.Collections.Generic;
6 2
7 3 namespace Implab.Automaton {
8 4 /// <summary>
9 5 /// Алфавит. ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²ΠΎ символов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π°Π·Π±ΠΈΡ‚Ρ‹ Π½Π° классы, ΠΏΡ€ΠΈ этом классы ΠΈΠΌΠ΅ΡŽΡ‚ Π½Π΅ΠΏΡ€Π΅Ρ€Ρ‹Π²Π½ΡƒΡŽ Π½ΡƒΠΌΠ΅Ρ€Π°Ρ†ΠΈΡŽ,
10 6 /// Ρ‡Ρ‚ΠΎ позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡ… Π² качСствС индСксов массивов.
11 7 /// </summary>
12 8 /// <remarks>
13 9 /// <para>Алфавит являСтся ΡΡŽΡ€ΡŒΠ΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ мноТСства символов Π² мноТСство индСксов, это позволяСт ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΎΠ² Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚Π°
14 10 /// для Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… символов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ для Π½Π΅Π³ΠΎ Π½Π΅ Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠΌΡ‹.</para>
15 11 /// </remarks>
16 12 /// <typeparam name="TSymbol">Вип символов.</typeparam>
17 13 public interface IAlphabet<TSymbol> {
18 14 /// <summary>
19 15 /// ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ классов символов Π² Π°Π»Ρ„Π°Π²ΠΈΡ‚Π΅.
20 16 /// </summary>
21 17 int Count { get; }
22 18
23 19 /// <summary>
24 20 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Π²Ρ…ΠΎΠ΄Π½ΠΎΠΉ символ Π² индСкс символа ΠΈΠ· Π°Π»Ρ„Π°Π²ΠΈΡ‚Π°.
25 21 /// </summary>
26 22 /// <param name="symobl">Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ символ</param>
27 23 /// <returns>ИндСкс Π² Π°Π»Ρ„Π°Π²ΠΈΡ‚Π΅</returns>
28 24 int Translate(TSymbol symobl);
29 25
30 26 bool Contains(TSymbol symbol);
31 27
32 28 IEnumerable<TSymbol> GetSymbols(int cls);
33 29 }
34 30 }
@@ -1,26 +1,25
1 using System;
2 using System.Collections.Generic;
1 using System.Collections.Generic;
3 2
4 3 namespace Implab.Automaton {
5 4 public interface IDFATableBuilder : IDFATable, ICollection<AutomatonTransition> {
6 5 /// <summary>
7 6 /// Marks the state as final.
8 7 /// </summary>
9 8 /// <param name="state">State.</param>
10 9 void MarkFinalState(int state);
11 10
12 11 void SetInitialState(int s);
13 12
14 13 /// <summary>
15 14 /// Increases if needed the input alphabet size to hold the specified symbol.
16 15 /// </summary>
17 16 /// <remarks>
18 17 /// <code>
19 18 /// AlphabetSize = Math.Max(AlphabetSize, symbol + 1)
20 19 /// </code>
21 20 /// </remarks>
22 21 /// <param name="symbol">Symbol.</param>
23 22 void AddSymbol(int symbol);
24 23 }
25 24 }
26 25
@@ -1,50 +1,47
1 using Implab;
2 using System;
1 using System;
3 2 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Linq;
6 3
7 4 namespace Implab.Automaton {
8 5 /// <summary>
9 6 /// Indexed alphabet is the finite set of symbols where each symbol has a zero-based unique index.
10 7 /// </summary>
11 8 /// <remarks>
12 9 /// Indexed alphabets are usefull in bulting efficient translations from source alphabet
13 10 /// to the input alphabet of the automaton. It's assumed that the index to the symbol match
14 11 /// is well known and documented.
15 12 /// </remarks>
16 13 public abstract class IndexedAlphabetBase<T> : MapAlphabet<T> {
17 14
18 15 protected IndexedAlphabetBase() :base(true, null) {
19 16 }
20 17
21 18 public abstract int GetSymbolIndex(T symbol);
22 19
23 20 /// <summary>
24 21 /// Gets the translation map from the index of the symbol to it's class this is usefull for the optimized input symbols transtaion.
25 22 /// </summary>
26 23 /// <remarks>
27 24 /// The map is continous and start from the symbol with zero code. The last symbol
28 25 /// in the map is the last classified symbol in the alphabet, i.e. the map can be
29 26 /// shorter then the whole alphabet.
30 27 /// </remarks>
31 28 /// <returns>The translation map.</returns>
32 29 public int[] GetTranslationMap() {
33 30 var map = new Dictionary<int, int>();
34 31
35 32 int max = 0;
36 33 foreach (var p in Mappings) {
37 34 var index = GetSymbolIndex(p.Key);
38 35 max = Math.Max(max, index);
39 36 map[index] = p.Value;
40 37 }
41 38
42 39 var result = new int[max + 1];
43 40
44 41 for (int i = 0; i < result.Length; i++)
45 42 map.TryGetValue(i, out result[i]);
46 43
47 44 return result;
48 45 }
49 46 }
50 47 }
@@ -1,49 +1,45
1 using Implab;
2 using System;
1 using System;
3 2 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 3
8 4 namespace Implab {
9 5 /// <summary>
10 6 /// ΠžΠ±Π΅Ρ€Ρ‚ΠΊΠ° для создания <c>IEqualityComparer</c> с использованиСм Π΄Π΅Π»Π΅Π³Π°Ρ‚ΠΎΠ² ΠΈΠ»ΠΈ лямда-Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ.
11 7 /// </summary>
12 8 /// <typeparam name="T">Π’ΠΈΠΏ сравниваСмых Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ</typeparam>
13 9 public class CustomEqualityComparer<T> : IEqualityComparer<T> {
14 10 Func<T, T, bool> m_equals;
15 11 Func<T, int> m_hash;
16 12
17 13 /// <summary>
18 14 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ с ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΌΠΈ функциями сравнСния Π½Π° Ρ€Π°Π²Π΅Ρ‚Π²ΠΎ ΠΈ получСния Ρ…Π΅Ρˆ-ΠΊΠΎΠ΄Π°.
19 15 /// </summary>
20 16 /// <param name="equality">Ѐункция ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° равСнство</param>
21 17 /// <param name="hash">Ѐункция получСния Ρ…Π΅ΡˆΠΊΠΎΠ΄Π°</param>
22 18 public CustomEqualityComparer(Func<T, T, bool> equality, Func<T, int> hash) {
23 19 Safe.ArgumentNotNull(equality, "equality");
24 20 Safe.ArgumentNotNull(hash, "hash");
25 21 m_hash = hash;
26 22 m_equals = equality;
27 23 }
28 24
29 25 /// <summary>
30 26 /// Π‘Ρ€Π°Π²Π½ΠΈΠ²Π°Π΅Ρ‚ Π΄Π²Π° знаСчния Π½Π° рСвСнство.
31 27 /// </summary>
32 28 /// <param name="x"></param>
33 29 /// <param name="y"></param>
34 30 /// <returns>Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ сравнСния Π½Π° равСнство</returns>
35 31 public bool Equals(T x, T y) {
36 32 return m_equals(x,y);
37 33 }
38 34
39 35 /// <summary>
40 36 /// ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Ρ…Π΅Ρˆ-ΠΊΠΎΠ΄ для ΡƒΠΊΠ°Π·Π°Π½Π½ΠΎΠ³ΠΎ значСния.
41 37 /// </summary>
42 38 /// <param name="obj"></param>
43 39 /// <remarks>Π Π°Π²Π½Ρ‹Π΅ знаСчния *Π΄ΠΎΠ»ΠΆΠ½Ρ‹* ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΉ Ρ…Π΅Ρˆ-ΠΊΠΎΠ΄.</remarks>
44 40 /// <returns>Π₯Сш-ΠΊΠΎΠ΄</returns>
45 41 public int GetHashCode(T obj) {
46 42 return m_hash(obj);
47 43 }
48 44 }
49 45 }
@@ -1,199 +1,198
1 1 // enable System.Diagnostics trace methods
2 2 #define TRACE
3 3
4 4 using System;
5 using System.Collections.Generic;
6 5 using System.Diagnostics;
7 using System.Linq;
8 using System.Text;
9 using System.Threading;
10 using System.Threading.Tasks;
6
7 #if NETFX_TRACE_BUG
8 using System.Threading;
9 #endif
11 10
12 11 namespace Implab.Diagnostics {
13 12 /// <summary>
14 13 /// Static class which creates an individual <see cref="TraceSource"/> for
15 14 /// the type specified in the parameter <typeparamref name="T"/> and uses
16 15 /// it to perform logging operations.
17 16 /// </summary>
18 17 /// <typeparam name="T">The type for which tracing is demanded.</typeparam>
19 18 public static class Trace<T> {
20 19
21 20 readonly static Lazy<TraceSource> _trace = new Lazy<TraceSource>(() => TraceSourceChannel<T>.Default.Source);
22 21
23 22 /// <summary>
24 23 /// The <see cref="TraceSource"/> associated with the current class.
25 24 /// TraceSource is created using <see cref="TraceSourceChannel{T}"/>.
26 25 /// </summary>
27 26 public static TraceSource TraceSource { get { return _trace.Value; } }
28 27
29 28 #if NETFX_TRACE_BUG
30 29 // AsyncLocal will store value inside the current execution context
31 30 // and will force it to be copied... not a very effective solution.
32 31 readonly static AsyncLocal<object> m_currentOperation = new AsyncLocal<object>();
33 32 #endif
34 33
35 34 /// <summary>
36 35 /// If this property is set then <see cref="Debug(string, object[])"/> will produce output.
37 36 /// </summary>
38 37 public static bool TraceVerbose {
39 38 get {
40 39 return TraceSource.Switch.ShouldTrace(TraceEventType.Verbose);
41 40 }
42 41 }
43 42
44 43 /// <summary>
45 44 /// If this property is set then <see cref="Log(string, object[])"/> will produce output.
46 45 /// </summary>
47 46 public static bool TraceInformation {
48 47 get {
49 48 return TraceSource.Switch.ShouldTrace(TraceEventType.Information);
50 49 }
51 50 }
52 51
53 52 /// <summary>
54 53 /// If this property is set then <see cref="Warn(string, object[])"/> will produce output.
55 54 /// </summary>
56 55 public static bool TraceWarnings {
57 56 get {
58 57 return TraceSource.Switch.ShouldTrace(TraceEventType.Warning);
59 58 }
60 59 }
61 60
62 61
63 62
64 63 /// <summary>
65 64 /// Starts the logical operation with the specified name, this name is usefull in logs.
66 65 /// </summary>
67 66 /// <param name="name">Name.</param>
68 67 #if NETFX_TRACE_BUG
69 68 public static void StartLogicalOperation(object name) {
70 69 m_currentOperation.Value = name;
71 70 Trace.CorrelationManager.StartLogicalOperation(name);
72 71 }
73 72
74 73 /// <summary>
75 74 /// Starts the logical operation nested to the current operation nested to the current one.
76 75 /// </summary>
77 76 public static void StartLogicalOperation() {
78 77 m_currentOperation.Value = new object();
79 78 Trace.CorrelationManager.StartLogicalOperation();
80 79
81 80 }
82 81 #else
83 82 public static void StartLogicalOperation(object name) {
84 83 Trace.CorrelationManager.StartLogicalOperation(name);
85 84 }
86 85
87 86 /// <summary>
88 87 /// Starts the logical operation nested to the current operation nested to the current one.
89 88 /// </summary>
90 89 public static void StartLogicalOperation() {
91 90 Trace.CorrelationManager.StartLogicalOperation();
92 91
93 92 }
94 93 #endif
95 94
96 95 /// <summary>
97 96 /// Ends the logical operation and restores the previous one.
98 97 /// </summary>
99 98 public static void StopLogicalOperation() {
100 99 Trace.CorrelationManager.StopLogicalOperation();
101 100 }
102 101
103 102 /// <summary>
104 103 /// Writes a debug message.
105 104 /// </summary>
106 105 /// <param name="format">Format.</param>
107 106 /// <param name="arguments">Arguments.</param>
108 107 [Conditional("DEBUG")]
109 108 public static void Debug(string format, params object[] arguments) {
110 109 TraceSource.TraceEvent(TraceEventType.Verbose, 0, format, arguments);
111 110 }
112 111
113 112 /// <summary>
114 113 /// Writes an informational message.
115 114 /// </summary>
116 115 /// <param name="format">Format.</param>
117 116 /// <param name="arguments">Arguments.</param>
118 117 [Conditional("TRACE")]
119 118 public static void Log(string format, params object[] arguments) {
120 119 TraceSource.TraceEvent(TraceEventType.Information, 0, format, arguments);
121 120 }
122 121
123 122 /// <summary>
124 123 /// Writes a warning message.
125 124 /// </summary>
126 125 /// <param name="format">Format.</param>
127 126 /// <param name="arguments">Arguments.</param>
128 127 public static void Warn(string format, params object[] arguments) {
129 128 TraceSource.TraceEvent(TraceEventType.Warning, 0, format, arguments);
130 129 }
131 130
132 131 /// <summary>
133 132 /// Writes a error message.
134 133 /// </summary>
135 134 /// <param name="format">Format.</param>
136 135 /// <param name="arguments">Arguments.</param>
137 136 public static void Error(string format, params object[] arguments) {
138 137 TraceSource.TraceEvent(TraceEventType.Error, 0, format, arguments);
139 138 }
140 139
141 140 public static void Error(Exception err) {
142 141 TraceSource.TraceData(TraceEventType.Error, 0, err);
143 142 }
144 143
145 144 /// <summary>
146 145 /// This method save the current activity, and transfers to the specified activity,
147 146 /// emits <see cref="TraceEventType.Start"/> and returns a scope of the new
148 147 /// activity.
149 148 /// </summary>
150 149 /// <param name="activityName">The name of the new activity/</param>
151 150 /// <param name="activityId">The identifier of the activity to which
152 151 /// the control will be transferred</param>
153 152 /// <returns>A scope of the new activity, dispose it to transfer
154 153 /// the control back to the original activity.</returns>
155 154 public static ActivityScope TransferActivity(string activityName, Guid activityId) {
156 155 var prev = Trace.CorrelationManager.ActivityId;
157 156
158 157 TraceSource.TraceTransfer(0, "Transfer", activityId);
159 158 Trace.CorrelationManager.ActivityId = activityId;
160 159 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
161 160
162 161 return new ActivityScope(TraceSource, prev, 0, activityName);
163 162 }
164 163
165 164 /// <summary>
166 165 /// Emits <see cref="TraceEventType.Start"/> and returns a scope of the
167 166 /// activity.
168 167 /// </summary>
169 168 /// <param name="activityName">The name of the activity to start</param>
170 169 /// <returns>A scope of the new activity, dispose it to emit
171 170 /// <see cref="TraceEventType.Stop"/> for the current activity.</returns>
172 171 public static ActivityScope StartActivity(string activityName) {
173 172 if (Trace.CorrelationManager.ActivityId == Guid.Empty)
174 173 Trace.CorrelationManager.ActivityId = Guid.NewGuid();
175 174
176 175 var prev = Trace.CorrelationManager.ActivityId;
177 176
178 177 TraceSource.TraceEvent(TraceEventType.Start, 0, activityName);
179 178 return new ActivityScope(TraceSource, prev, 0, activityName);
180 179 }
181 180
182 181 /// <summary>
183 182 /// Creates new <see cref="LogicalOperation(string)"/> and calls
184 183 /// to <see cref="CorrelationManager.StartLogicalOperation(object)"/>
185 184 /// passing the created operation as identity. Calls
186 185 /// <see cref="TraceSource.TraceData(TraceEventType, int, object)"/>
187 186 /// to notify listeners on operation start.
188 187 /// </summary>
189 188 /// <param name="name">The name of the logical operation.</param>
190 189 /// <returns>Logical operation scope, disposing it will stop
191 190 /// logical operation and notify trace listeners.</returns>
192 191 public static LogicalOperationScope LogicalOperation(string name) {
193 192 var operation = new LogicalOperation(name);
194 193 TraceSource.TraceData(TraceEventType.Information, TraceEventCodes.StartLogicalOperation, operation);
195 194 StartLogicalOperation(operation);
196 195 return new LogicalOperationScope(TraceSource, operation);
197 196 }
198 197 }
199 198 }
@@ -1,86 +1,85
1 1 using System;
2 2 using System.Collections.Generic;
3 using System.Diagnostics;
4 3 using Implab.Parallels;
5 4
6 5 namespace Implab.Diagnostics {
7 6 public class TraceRegistry: IObservable<TraceChannel> {
8 7
9 8 class Subscription : IDisposable {
10 9 readonly WeakReference<TraceRegistry> m_registry;
11 10
12 11 public Subscription(TraceRegistry registry) {
13 12 m_registry = new WeakReference<TraceRegistry>(registry);
14 13 }
15 14
16 15 public void Dispose() {
17 16 TraceRegistry t;
18 17 if (m_registry.TryGetTarget(out t))
19 18 t.RemoveSubscription(this);
20 19 }
21 20 }
22 21
23 22 /// <summary>
24 23 /// The global collection of available diagnostic channels
25 24 /// </summary>
26 25 /// <returns></returns>
27 26 public static TraceRegistry Global { get; } = new TraceRegistry();
28 27
29 28 readonly object m_lock = new object();
30 29
31 30 readonly Dictionary<object, IObserver<TraceChannel>> m_subscriptions = new Dictionary<object, IObserver<TraceChannel>>();
32 31 readonly SimpleAsyncQueue<TraceChannel> m_channels = new SimpleAsyncQueue<TraceChannel>();
33 32
34 33 public void Register(TraceChannel channel) {
35 34 // notifications can run in parallel
36 35 IObserver<TraceChannel>[] handlers = null;
37 36
38 37 lock(m_lock) {
39 38 m_channels.Enqueue(channel);
40 39 if (m_subscriptions.Count > 0) {
41 40 handlers = new IObserver<TraceChannel>[m_subscriptions.Count];
42 41 m_subscriptions.Values.CopyTo(handlers, 0);
43 42 }
44 43 }
45 44
46 45 if (handlers != null)
47 46 foreach(var h in handlers)
48 47 h.OnNext(channel);
49 48 }
50 49
51 50 /// <summary>
52 51 /// Subscribes the specified handler to notifications about new trace
53 52 /// channels
54 53 /// </summary>
55 54 /// <param name="handler"></param>
56 55 /// <returns></returns>
57 56 public IDisposable Subscribe(IObserver<TraceChannel> handler) {
58 57 Safe.ArgumentNotNull(handler, nameof(handler));
59 58
60 59 var cookie = new Subscription(this);
61 60
62 61 IEnumerable<TraceChannel> snap;
63 62
64 63 // lock to ensure that no new channels will be added
65 64 // while the subscription is added
66 65 lock(m_lock) {
67 66 m_subscriptions.Add(cookie, handler);
68 67 snap = m_channels.Snapshot();
69 68 }
70 69
71 70 // announce previously declared channels if required
72 71 if (snap != null) {
73 72 foreach(var c in snap)
74 73 handler.OnNext(c);
75 74 }
76 75
77 76 // return the subscription
78 77 return cookie;
79 78 }
80 79
81 80 void RemoveSubscription(object cookie) {
82 81 lock(m_lock)
83 82 m_subscriptions.Remove(cookie);
84 83 }
85 84 }
86 85 } No newline at end of file
@@ -1,33 +1,32
1 1 using System;
2 2 using System.Threading;
3 using TraceSource = System.Diagnostics.TraceSource;
4 3
5 4 namespace Implab.Diagnostics {
6 5 /// <summary>
7 6 /// This class is used to provide a single <see cref="TraceSourceChannel"/>
8 7 /// instance for the specified class in <typeparamref name="T"/> parameter.
9 8 /// </summary>
10 9 /// <typeparam name="T">
11 10 /// The class for which <see cref="TraceSourceChannel"/> is required.
12 11 /// </typeparam>
13 12 /// <remarks>
14 13 /// The <see cref="TraceSourceChannel"/> instance will be created on demand
15 14 /// and automatically registered in <see cref="TraceRegistry.Global"/>.
16 15 /// </remarks>
17 16 public static class TraceSourceChannel<T> {
18 17 static Lazy<TraceSourceChannel> _traceSource = new Lazy<TraceSourceChannel>(CreateChannel, LazyThreadSafetyMode.ExecutionAndPublication);
19 18
20 19 /// <summary>
21 20 /// The default <see cref="TraceSourceChannel"/> instance.
22 21 /// </summary>
23 22 public static TraceSourceChannel Default { get { return _traceSource.Value; } }
24 23
25 24 static TraceSourceChannel CreateChannel() {
26 25 var channel = new TraceSourceChannel(typeof(T), typeof(T).FullName);
27 26
28 27 TraceRegistry.Global.Register(channel);
29 28
30 29 return channel;
31 30 }
32 31 }
33 32 } No newline at end of file
@@ -1,42 +1,39
1 1 using Implab.Automaton;
2 using System;
3 2 using System.Collections.Generic;
4 3 using System.Linq;
5 4 using System.Runtime.CompilerServices;
6 using System.Text;
7 using System.Threading.Tasks;
8 5
9 6 namespace Implab.Formats {
10 7 public class CharMap : IAlphabet<char> {
11 8 readonly char m_min;
12 9 readonly char m_max;
13 10 readonly int[] m_map;
14 11
15 12 public CharMap(char min, int[] map) {
16 13 Safe.ArgumentNotNull(map, nameof(map));
17 14 Count = map.Max()+1;
18 15 m_min = min;
19 16 m_map = map;
20 17 m_max = (char)(min + map.Length);
21 18 }
22 19
23 20 public int Count {
24 21 get; private set;
25 22 }
26 23
27 24 public bool Contains(char symbol) {
28 25 return symbol >= m_min && symbol <= m_max && m_map[symbol-m_min] != AutomatonConst.UnclassifiedInput;
29 26 }
30 27
31 28 public IEnumerable<char> GetSymbols(int cls) {
32 29 for (var i = 0; i < m_map.Length; i++)
33 30 if (m_map[i] == cls)
34 31 yield return (char)(i + m_min);
35 32 }
36 33
37 34 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 35 public int Translate(char symbol) {
39 36 return symbol >= m_min && symbol <= m_max ? m_map[symbol-m_min] : AutomatonConst.UnclassifiedInput;
40 37 }
41 38 }
42 39 }
@@ -1,128 +1,123
1 1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 2 using System.Diagnostics;
5 using System.Linq;
6 3 using System.Runtime.CompilerServices;
7 using System.Text;
8 using System.Threading.Tasks;
9 4
10 5 namespace Implab.Formats {
11 6
12 7 /// <summary>
13 8 /// Fast input scanner for max 255 states and 255 input chacters.
14 9 /// </summary>
15 10 /// <typeparam name="TTag"></typeparam>
16 11 /// <remarks>
17 12 /// <para>
18 13 /// Creates a one rank array to store automa transition table, each entry in this table is byte, to make this table small enough to fit L1 cache.
19 14 /// </para>
20 15 /// <para>
21 16 /// Each entry is addressed as <c>(state << 8) | input</c> which make this quite fast to get the next state. Each input symbol below 255 is treated as 255.
22 17 /// </para>
23 18 /// </remarks>
24 19 public class FastInputScanner<TTag> {
25 20 const int StateShift = 8;
26 21 const int StateMask = ~((1 << StateShift) - 1);
27 22 const int AlphabetSize = 1 << StateShift;
28 23 const int UnclassifiedInput = (1 << StateShift) - 1;
29 24 const byte UnreachableState = byte.MaxValue;
30 25
31 26 readonly TTag[] m_tags;
32 27 readonly bool[] m_final;
33 28
34 29 readonly byte m_initialState;
35 30 readonly byte[] m_dfa;
36 31
37 32 int m_position;
38 33 byte m_state;
39 34
40 35 protected FastInputScanner(byte[] table, bool[] final, TTag[] tags, byte initial) {
41 36 m_dfa = table;
42 37 m_final = final;
43 38 m_tags = tags;
44 39 m_initialState = initial;
45 40 }
46 41
47 42 public FastInputScanner(int[,] dfaTable, bool[] finalStates, TTag[] tags, int initialState, int[] inputMap) {
48 43 var states = dfaTable.GetLength(0);
49 44 Debug.Assert(states < byte.MaxValue);
50 45
51 46 m_dfa = new byte[states << StateShift];
52 47 m_initialState = (byte)initialState;
53 48
54 49 m_tags = tags;
55 50 m_final = finalStates;
56 51
57 52 // iterate over states
58 53 for(int si = 0; si < states; si++) {
59 54 // state offset for the new table
60 55 var offset = si << StateShift;
61 56
62 57 // iterate over alphabet
63 58 for(int a = 0; a < AlphabetSize; a++) {
64 59 var next = dfaTable[si, a < inputMap.Length ? inputMap[a] : AutomatonConst.UnclassifiedInput];
65 60 if (next == AutomatonConst.UnreachableState)
66 61 next = UnreachableState;
67 62
68 63 m_dfa[offset | a] = (byte)next;
69 64 }
70 65 }
71 66 }
72 67
73 68 public TTag Tag {
74 69 [MethodImpl(MethodImplOptions.AggressiveInlining)]
75 70 get {
76 71 return m_tags[m_state];
77 72 }
78 73 }
79 74
80 75 public int Position {
81 76 [MethodImpl(MethodImplOptions.AggressiveInlining)]
82 77 get {
83 78 return m_position;
84 79 }
85 80 }
86 81
87 82 public bool IsFinal {
88 83 [MethodImpl(MethodImplOptions.AggressiveInlining)]
89 84 get {
90 85 return m_final[m_state];
91 86 }
92 87 }
93 88
94 89 [MethodImpl(MethodImplOptions.AggressiveInlining)]
95 90 public void ResetState() {
96 91 m_state = m_initialState;
97 92 }
98 93
99 94 public FastInputScanner<TTag> Clone() {
100 95 var clone = new FastInputScanner<TTag>(m_dfa, m_final, m_tags, m_initialState);
101 96 clone.m_state = m_state;
102 97 clone.m_position = m_position;
103 98 return clone;
104 99 }
105 100
106 101 public bool Scan(char[] data, int offset, int max) {
107 102 var next = m_state;
108 103
109 104 m_position = offset;
110 105 while (m_position < max) {
111 106 var ch = data[m_position];
112 107
113 108 next = m_dfa[(ch >= AlphabetSize ? (next << StateShift) | UnclassifiedInput : (next << StateShift) | ch)];
114 109
115 110 if (next == UnreachableState)
116 111 // scanner stops at the next position after the last recognized symbol
117 112 return false;
118 113
119 114 m_state = next;
120 115 m_position++;
121 116 }
122 117
123 118 return true;
124 119 }
125 120
126 121
127 122 }
128 123 }
@@ -1,73 +1,72
1 using Implab;
2 using System;
1 using System;
3 2 using System.Collections.Generic;
4 3 using System.Linq;
5 4 using Implab.Automaton;
6 5 using Implab.Automaton.RegularExpressions;
7 6
8 7 namespace Implab.Formats {
9 8 /// <summary>
10 9 /// Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ абстрактный класс. Π“Ρ€Π°ΠΌΠΌΠ°Ρ‚ΠΈΠΊΠ°, позволяСт Ρ„ΠΎΡ€ΠΌΡƒΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ выраТСния Π½Π°Π΄ Π°Π»Ρ„Π°Π²ΠΈΡ‚ΠΎΠΌ Ρ‚ΠΈΠΏΠ° <c>char</c>.
11 10 /// </summary>
12 11 public abstract class Grammar<TSymbol> {
13 12
14 13 protected abstract IAlphabetBuilder<TSymbol> AlphabetBuilder {
15 14 get;
16 15 }
17 16
18 17 protected SymbolToken UnclassifiedToken() {
19 18 return new SymbolToken(AutomatonConst.UnclassifiedInput);
20 19 }
21 20
22 21 protected void DefineAlphabet(IEnumerable<TSymbol> alphabet) {
23 22 Safe.ArgumentNotNull(alphabet, "alphabet");
24 23
25 24 foreach (var ch in alphabet)
26 25 AlphabetBuilder.DefineSymbol(ch);
27 26 }
28 27
29 28 protected Token SymbolToken(TSymbol symbol) {
30 29 return Token.New(TranslateOrAdd(symbol));
31 30 }
32 31
33 32 protected Token SymbolToken(IEnumerable<TSymbol> symbols) {
34 33 Safe.ArgumentNotNull(symbols, "symbols");
35 34
36 35 return Token.New(TranslateOrAdd(symbols).ToArray());
37 36 }
38 37
39 38 protected Token SymbolSetToken(params TSymbol[] set) {
40 39 return SymbolToken(set);
41 40 }
42 41
43 42 int TranslateOrAdd(TSymbol ch) {
44 43 var t = AlphabetBuilder.Translate(ch);
45 44 if (t == AutomatonConst.UnclassifiedInput)
46 45 t = AlphabetBuilder.DefineSymbol(ch);
47 46 return t;
48 47 }
49 48
50 49 IEnumerable<int> TranslateOrAdd(IEnumerable<TSymbol> symbols) {
51 50 return symbols.Distinct().Select(TranslateOrAdd);
52 51 }
53 52
54 53 int TranslateOrDie(TSymbol ch) {
55 54 var t = AlphabetBuilder.Translate(ch);
56 55 if (t == AutomatonConst.UnclassifiedInput)
57 56 throw new ApplicationException(String.Format("Symbol '{0}' is UNCLASSIFIED", ch));
58 57 return t;
59 58 }
60 59
61 60 IEnumerable<int> TranslateOrDie(IEnumerable<TSymbol> symbols) {
62 61 return symbols.Distinct().Select(TranslateOrDie);
63 62 }
64 63
65 64 protected Token SymbolTokenExcept(IEnumerable<TSymbol> symbols) {
66 65 Safe.ArgumentNotNull(symbols, "symbols");
67 66
68 67 return Token.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() );
69 68 }
70 69 }
71 70
72 71
73 72 }
@@ -1,84 +1,79
1 1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 2 using System.Runtime.CompilerServices;
6 using System.Text;
7 using System.Threading.Tasks;
8 3
9 4 namespace Implab.Formats {
10 5 public class InputScanner<TTag> {
11 6 readonly TTag[] m_tags;
12 7 readonly int m_initialState;
13 8 readonly int[,] m_dfa;
14 9 readonly CharMap m_alphabet;
15 10 readonly bool[] m_final;
16 11
17 12 int m_position;
18 13 int m_state;
19 14
20 15 public InputScanner(int[,] dfaTable, bool[] finalStates, TTag[] tags, int initialState, CharMap alphabet) {
21 16 Safe.ArgumentNotNull(dfaTable, nameof(dfaTable));
22 17 Safe.ArgumentNotNull(finalStates, nameof(finalStates));
23 18 Safe.ArgumentNotNull(tags, nameof(tags));
24 19 Safe.ArgumentNotNull(alphabet, nameof(alphabet));
25 20
26 21 m_dfa = dfaTable;
27 22 m_final = finalStates;
28 23 m_tags = tags;
29 24 m_initialState = initialState;
30 25 m_alphabet = alphabet;
31 26 }
32 27
33 28 public TTag Tag {
34 29 [MethodImpl(MethodImplOptions.AggressiveInlining)]
35 30 get {
36 31 return m_tags[m_state];
37 32 }
38 33 }
39 34
40 35 public int Position {
41 36 [MethodImpl(MethodImplOptions.AggressiveInlining)]
42 37 get {
43 38 return m_position;
44 39 }
45 40 }
46 41
47 42 public bool IsFinal {
48 43 [MethodImpl(MethodImplOptions.AggressiveInlining)]
49 44 get {
50 45 return m_final[m_state];
51 46 }
52 47 }
53 48
54 49 [MethodImpl(MethodImplOptions.AggressiveInlining)]
55 50 public void ResetState() {
56 51 m_state = m_initialState;
57 52 }
58 53
59 54 public InputScanner<TTag> Clone() {
60 55 var clone = new InputScanner<TTag>(m_dfa, m_final, m_tags, m_initialState, m_alphabet);
61 56 clone.m_state = m_state;
62 57 clone.m_position = m_position;
63 58 return clone;
64 59 }
65 60
66 61 //[MethodImpl(MethodImplOptions.AggressiveInlining)]
67 62 public bool Scan(char[] data, int offset, int max) {
68 63 var next = m_state;
69 64
70 65 while(offset < max) {
71 66 next = m_dfa[next, m_alphabet.Translate(data[offset])];
72 67 if (next == AutomatonConst.UnreachableState) {
73 68 // scanner stops on the next position after last recognized symbol
74 69 m_position = offset;
75 70 return false;
76 71 }
77 72 m_state = next;
78 73 offset++;
79 74 }
80 75 m_position = offset;
81 76 return true;
82 77 }
83 78 }
84 79 }
@@ -1,318 +1,317
1 1 using System;
2 2 using System.Diagnostics;
3 3 using System.IO;
4 4 using Implab.Automaton;
5 5 using Implab.Automaton.RegularExpressions;
6 6 using System.Linq;
7 7 using Implab.Components;
8 8 using System.Collections.Generic;
9 9 using System.Text;
10 using System.Globalization;
11 10
12 11 namespace Implab.Formats.Json {
13 12 /// <summary>
14 13 /// Pull парсСр JSON Π΄Π°Π½Π½Ρ‹Ρ….
15 14 /// </summary>
16 15 /// <remarks>
17 16 /// Π‘Π»Π΅Π΄ΡƒΠ΅Ρ‚ ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ†ΠΈΡŽ свойства <see cref="Level"/>,
18 17 /// ΠΎΠ½ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², ΠΎΠ΄Π½Π°ΠΊΠΎ Π·Π°ΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉ
19 18 /// элСмСнт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° ΠΈ массива ΠΈΠΌΠ΅Π΅Ρ‚ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ мСньшС, Ρ‡Π΅ΠΌ сам ΠΎΠ±ΡŠΠ΅ΠΊΡ‚.
20 19 /// <code>
21 20 /// { // Level = 1
22 21 /// "name" : "Peter", // Level = 1
23 22 /// "address" : { // Level = 2
24 23 /// city : "Stern" // Level = 2
25 24 /// } // Level = 1
26 25 /// } // Level = 0
27 26 /// </code>
28 27 /// </remarks>
29 28 public class JsonReader : Disposable {
30 29
31 30 enum MemberContext {
32 31 MemberName,
33 32 MemberValue
34 33 }
35 34
36 35 #region Parser rules
37 36 struct ParserContext {
38 37 readonly int[,] m_dfa;
39 38 int m_state;
40 39
41 40 readonly JsonElementContext m_elementContext;
42 41
43 42 public ParserContext(int[,] dfa, int state, JsonElementContext context) {
44 43 m_dfa = dfa;
45 44 m_state = state;
46 45 m_elementContext = context;
47 46 }
48 47
49 48 public bool Move(JsonTokenType token) {
50 49 var next = m_dfa[m_state, (int)token];
51 50 if (next == AutomatonConst.UnreachableState)
52 51 return false;
53 52 m_state = next;
54 53 return true;
55 54 }
56 55
57 56 public JsonElementContext ElementContext {
58 57 get { return m_elementContext; }
59 58 }
60 59 }
61 60
62 61 static readonly ParserContext _jsonContext;
63 62 static readonly ParserContext _objectContext;
64 63 static readonly ParserContext _arrayContext;
65 64
66 65 static JsonReader() {
67 66
68 67 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
69 68 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
70 69
71 70 var objectExpression = memberExpression
72 71 .Cat(
73 72 MakeToken(JsonTokenType.ValueSeparator)
74 73 .Cat(memberExpression)
75 74 .EClosure()
76 75 )
77 76 .Optional()
78 77 .Cat(MakeToken(JsonTokenType.EndObject))
79 78 .End();
80 79
81 80 var arrayExpression = valueExpression
82 81 .Cat(
83 82 MakeToken(JsonTokenType.ValueSeparator)
84 83 .Cat(valueExpression)
85 84 .EClosure()
86 85 )
87 86 .Optional()
88 87 .Cat(MakeToken(JsonTokenType.EndArray))
89 88 .End();
90 89
91 90 var jsonExpression = valueExpression.End();
92 91
93 92 _jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None);
94 93 _objectContext = CreateParserContext(objectExpression, JsonElementContext.Object);
95 94 _arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array);
96 95 }
97 96
98 97 static Token MakeToken(params JsonTokenType[] input) {
99 98 return Token.New( input.Select(t => (int)t).ToArray() );
100 99 }
101 100
102 101 static ParserContext CreateParserContext(Token expr, JsonElementContext context) {
103 102
104 103 var dfa = new DFATable();
105 104 var builder = new RegularExpressionVisitor(dfa);
106 105 expr.Accept(builder);
107 106 builder.BuildDFA();
108 107
109 108 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
110 109 }
111 110
112 111 #endregion
113 112
114 113 readonly JsonScanner m_scanner;
115 114 // json starts from the value context and may content even a single literal
116 115 MemberContext m_memberContext = MemberContext.MemberValue;
117 116
118 117 JsonElementType m_elementType;
119 118 string m_elementValue;
120 119 string m_memberName = String.Empty;
121 120
122 121 Stack<ParserContext> m_stack = new Stack<ParserContext>();
123 122 ParserContext m_context = _jsonContext;
124 123
125 124 /// <summary>
126 125 /// Π‘ΠΎΠ·Π΄Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ парсСр Π½Π° основС строки, содСрТащСй JSON
127 126 /// </summary>
128 127 /// <param name="text"></param>
129 128 JsonReader(JsonScanner scanner) {
130 129 m_scanner = scanner;
131 130 }
132 131
133 132 public int Level {
134 133 get { return m_stack.Count; }
135 134 }
136 135
137 136 /// <summary>
138 137 /// Π’ΠΈΠΏ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ элСмСнта Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ стоит парсСр.
139 138 /// </summary>
140 139 public JsonElementType ElementType {
141 140 get { return m_elementType; }
142 141 }
143 142
144 143 /// <summary>
145 144 /// Имя элСмСнта - имя свойства Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°. Для элСмСнтов массивов ΠΈ ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ всСгда
146 145 /// пустая строка.
147 146 /// </summary>
148 147 public string ElementName {
149 148 get { return m_memberName; }
150 149 }
151 150
152 151 /// <summary>
153 152 /// Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ элСмСнта. Волько для элСмСнтов Ρ‚ΠΈΠΏΠ° <see cref="JsonElementType.Value"/>, для ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… <c>null</c>
154 153 /// </summary>
155 154 public string ElementValue {
156 155 get { return m_elementValue; }
157 156 }
158 157
159 158 /// <summary>
160 159 /// Π§ΠΈΡ‚Π°Π΅Ρ‚ ΡΠ»Π΅ΡŽΡƒΠ΄ΡƒΡ‰ΠΈΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ· ΠΏΠΎΡ‚ΠΎΠΊΠ°
161 160 /// </summary>
162 161 /// <returns><c>true</c> - опСрация чтСния ΠΏΡ€ΠΎΡˆΠ»Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, <c>false</c> - ΠΊΠΎΠ½Π΅Ρ† Π΄Π°Π½Π½Ρ‹Ρ…</returns>
163 162 public bool Read() {
164 163 string tokenValue;
165 164 JsonTokenType tokenType;
166 165
167 166 m_memberName = String.Empty;
168 167
169 168 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
170 169 if(!m_context.Move(tokenType))
171 170 UnexpectedToken(tokenValue, tokenType);
172 171
173 172 switch (tokenType) {
174 173 case JsonTokenType.BeginObject:
175 174 m_stack.Push(m_context);
176 175 m_context = _objectContext;
177 176
178 177 m_elementValue = null;
179 178 m_memberContext = MemberContext.MemberName;
180 179 m_elementType = JsonElementType.BeginObject;
181 180 return true;
182 181 case JsonTokenType.EndObject:
183 182 if (m_stack.Count == 0)
184 183 UnexpectedToken(tokenValue, tokenType);
185 184 m_context = m_stack.Pop();
186 185
187 186 m_elementValue = null;
188 187 m_elementType = JsonElementType.EndObject;
189 188 return true;
190 189 case JsonTokenType.BeginArray:
191 190 m_stack.Push(m_context);
192 191 m_context = _arrayContext;
193 192
194 193 m_elementValue = null;
195 194 m_memberContext = MemberContext.MemberValue;
196 195 m_elementType = JsonElementType.BeginArray;
197 196 return true;
198 197 case JsonTokenType.EndArray:
199 198 if (m_stack.Count == 0)
200 199 UnexpectedToken(tokenValue, tokenType);
201 200 m_context = m_stack.Pop();
202 201
203 202 m_elementValue = null;
204 203 m_elementType = JsonElementType.EndArray;
205 204 return true;
206 205 case JsonTokenType.String:
207 206 if (m_memberContext == MemberContext.MemberName) {
208 207 m_memberName = tokenValue;
209 208 break;
210 209 }
211 210 m_elementType = JsonElementType.Value;
212 211 m_elementValue = tokenValue;
213 212 return true;
214 213 case JsonTokenType.Number:
215 214 m_elementType = JsonElementType.Value;
216 215 m_elementValue = tokenValue;
217 216 return true;
218 217 case JsonTokenType.Literal:
219 218 m_elementType = JsonElementType.Value;
220 219 m_elementValue = tokenValue == "null" ? null : tokenValue;
221 220 return true;
222 221 case JsonTokenType.NameSeparator:
223 222 m_memberContext = MemberContext.MemberValue;
224 223 break;
225 224 case JsonTokenType.ValueSeparator:
226 225 m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
227 226 break;
228 227 default:
229 228 UnexpectedToken(tokenValue, tokenType);
230 229 break;
231 230 }
232 231 }
233 232 if (m_context.ElementContext != JsonElementContext.None)
234 233 throw new ParserException("Unexpedted end of data");
235 234
236 235 Eof = true;
237 236
238 237 return false;
239 238 }
240 239
241 240 object ParseLiteral(string literal) {
242 241 switch (literal) {
243 242 case "null":
244 243 return null;
245 244 case "false":
246 245 return false;
247 246 case "true":
248 247 return true;
249 248 default:
250 249 UnexpectedToken(literal, JsonTokenType.Literal);
251 250 return null; // avoid compliler error
252 251 }
253 252 }
254 253
255 254 void UnexpectedToken(object value, JsonTokenType tokenType) {
256 255 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
257 256 }
258 257
259 258
260 259 /// <summary>
261 260 /// ΠŸΡ€ΠΈΠ·Π½Π°ΠΊ ΠΊΠΎΠ½Ρ†Π° ΠΏΠΎΡ‚ΠΎΠΊΠ°
262 261 /// </summary>
263 262 public bool Eof {
264 263 get;
265 264 private set;
266 265 }
267 266
268 267 protected override void Dispose(bool disposing) {
269 268 if (disposing)
270 269 m_scanner.Dispose();
271 270 }
272 271
273 272 /// <summary>
274 273 /// ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ Π² ΠΊΠΎΠ½Π΅Ρ† Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.
275 274 /// </summary>
276 275 public void SeekElementEnd() {
277 276 var level = Level - 1;
278 277
279 278 Debug.Assert(level >= 0);
280 279
281 280 while (Level != level)
282 281 Read();
283 282 }
284 283
285 284 public static JsonReader Create(string file, Encoding encoding) {
286 285 return new JsonReader(JsonTextScanner.Create(file, encoding));
287 286 }
288 287
289 288 public static JsonReader Create(string file) {
290 289 return new JsonReader(JsonTextScanner.Create(file));
291 290 }
292 291
293 292 public static JsonReader Create(Stream stream, Encoding encoding) {
294 293 return new JsonReader(JsonTextScanner.Create(stream, encoding));
295 294 }
296 295
297 296 public static JsonReader Create(Stream stream) {
298 297 return new JsonReader(JsonTextScanner.Create(stream));
299 298 }
300 299
301 300 public static JsonReader Create(TextReader reader) {
302 301 return new JsonReader(JsonTextScanner.Create(reader));
303 302 }
304 303
305 304 public static JsonReader ParseString(string data) {
306 305 return new JsonReader(JsonStringScanner.Create(data));
307 306 }
308 307
309 308 public static JsonReader ParseString(string data, int offset, int length) {
310 309 return new JsonReader(JsonStringScanner.Create(data, offset, length));
311 310 }
312 311
313 312 public static JsonReader ParseString(char[] data, int offset, int lenght) {
314 313 return new JsonReader(JsonStringScanner.Create(data, offset, lenght));
315 314 }
316 315 }
317 316
318 317 }
@@ -1,190 +1,187
1 using System;
2 using System.Globalization;
3 using Implab.Automaton;
1 using Implab.Automaton;
4 2 using System.Text;
5 3 using Implab.Components;
6 using System.IO;
7 4
8 5 namespace Implab.Formats.Json {
9 6 /// <summary>
10 7 /// Π‘ΠΊΠ°Π½Π½Π΅Ρ€ (лСксСр), Ρ€Π°Π·Π±ΠΈΠ²Π°ΡŽΡ‰ΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ символов Π½Π° Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ JSON.
11 8 /// </summary>
12 9 public abstract class JsonScanner : Disposable {
13 10 readonly FastInputScanner<JsonGrammar.TokenType> m_jsonContext = JsonGrammar.CreateJsonExpressionScanner();
14 11 readonly FastInputScanner<JsonGrammar.TokenType> m_stringContext = JsonGrammar.CreateStringExpressionScanner();
15 12
16 13 readonly char[] m_unescapeBuf = new char[4];
17 14 readonly char[] m_buffer;
18 15 int m_length;
19 16 int m_pos;
20 17 readonly StringBuilder m_tokenBuilder = new StringBuilder();
21 18
22 19 protected JsonScanner(char[] buffer, int pos, int length) {
23 20 m_buffer = buffer;
24 21 m_pos = pos;
25 22 m_length = length;
26 23 }
27 24
28 25 bool ReadChunk(FastInputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
29 26 scanner.ResetState();
30 27
31 28 while(scanner.Scan(m_buffer, m_pos, m_length)) {
32 29 // scanner requests new data
33 30
34 31 if (m_pos != m_length) // capture results for the future
35 32 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
36 33
37 34 // read next data
38 35 m_length = Read(m_buffer, 0, m_buffer.Length);
39 36
40 37 if (m_length == 0) {
41 38 // no data is read
42 39 if (scanner.Position == m_pos) {
43 40 // scanned hasn't moved, that's the end
44 41 m_pos = 0;
45 42 tokenType = JsonGrammar.TokenType.None;
46 43 return false;
47 44 }
48 45
49 46 if (scanner.IsFinal) {
50 47 m_pos = 0;
51 48 tokenType = scanner.Tag;
52 49 return true;
53 50 } else {
54 51 throw new ParserException("Unexpected EOF");
55 52 }
56 53 }
57 54
58 55 m_pos = 0;
59 56 }
60 57 var scannerPos = scanner.Position;
61 58
62 59 // scanner stops as scannerPos
63 60 if (!scanner.IsFinal)
64 61 throw new ParserException($"Unexpected character '{m_buffer[scannerPos + 1]}'");
65 62
66 63 tokenType = scanner.Tag;
67 64 if (scannerPos != m_pos && tokenType == JsonGrammar.TokenType.Number || tokenType == JsonGrammar.TokenType.Literal)
68 65 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
69 66
70 67 m_pos = scannerPos;
71 68 return true;
72 69 }
73 70
74 71 bool ReadStringChunk(FastInputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
75 72 scanner.ResetState();
76 73
77 74 while (scanner.Scan(m_buffer, m_pos, m_length)) {
78 75 // scanner requests new data
79 76
80 77 if (m_pos != m_length) // capture results for the future
81 78 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
82 79
83 80 // read next data
84 81 m_length = Read(m_buffer, 0, m_buffer.Length);
85 82
86 83 if (m_length == 0) {
87 84 // no data is read
88 85 if (scanner.Position == m_pos) {
89 86 // scanned hasn't moved, that's the end
90 87 m_pos = 0;
91 88 tokenType = JsonGrammar.TokenType.None;
92 89 return false;
93 90 }
94 91
95 92 if (scanner.IsFinal) {
96 93 m_pos = 0;
97 94 tokenType = scanner.Tag;
98 95 return true;
99 96 } else {
100 97 throw new ParserException("Unexpected EOF");
101 98 }
102 99 }
103 100
104 101 m_pos = 0;
105 102 }
106 103 var scannerPos = scanner.Position;
107 104
108 105 // scanner stops as scannerPos
109 106 if (!scanner.IsFinal)
110 107 throw new ParserException($"Unexpected character '{m_buffer[scannerPos]}'");
111 108
112 109 if (scannerPos != m_pos) {
113 110 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
114 111 m_pos = scannerPos;
115 112 }
116 113 tokenType = scanner.Tag;
117 114 return true;
118 115 }
119 116
120 117 protected abstract int Read(char[] buffer, int offset, int size);
121 118
122 119
123 120 /// <summary>
124 121 /// Π§ΠΈΡ‚Π°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ лСксичСский элСмСнт ΠΈΠ· Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ….
125 122 /// </summary>
126 123 /// <param name="tokenValue">Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΎΠΊΠ΅Π½Π°.</param>
127 124 /// <param name="tokenType">Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ‚ΠΈΠΏ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΎΠΊΠ΅Π½Π°.</param>
128 125 /// <returns><c>true</c> - Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ. <c>false</c> - достигнут ΠΊΠΎΠ½Π΅Ρ† Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…</returns>
129 126 /// <remarks>Π’ случС Ссли Ρ‚ΠΎΠΊΠ΅Π½ Π½Π΅ распознаСтся, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅. ЗначСния Ρ‚ΠΎΠΊΠ΅Π½ΠΎΠ² ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ, Ρ‚.Π΅.
130 127 /// Π² строках ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ экранированныС символы, числа становтся Ρ‚ΠΈΠΏΠ° double.</remarks>
131 128 public bool ReadToken(out string tokenValue, out JsonTokenType tokenType) {
132 129 JsonGrammar.TokenType tag;
133 130 m_tokenBuilder.Clear();
134 131 while (ReadChunk(m_jsonContext, out tag)) {
135 132 switch (tag) {
136 133 case JsonGrammar.TokenType.StringBound:
137 134 tokenValue = ReadString();
138 135 tokenType = JsonTokenType.String;
139 136 break;
140 137 case JsonGrammar.TokenType.Number:
141 138 tokenValue = m_tokenBuilder.ToString();
142 139 tokenType = JsonTokenType.Number;
143 140 break;
144 141 case JsonGrammar.TokenType.Literal:
145 142 tokenType = JsonTokenType.Literal;
146 143 tokenValue = m_tokenBuilder.ToString();
147 144 break;
148 145 case JsonGrammar.TokenType.Whitespace:
149 146 m_tokenBuilder.Clear();
150 147 continue;
151 148 default:
152 149 tokenType = (JsonTokenType)tag;
153 150 tokenValue = null;
154 151 break;
155 152 }
156 153 return true;
157 154 }
158 155 tokenValue = null;
159 156 tokenType = JsonTokenType.None;
160 157 return false;
161 158 }
162 159
163 160 string ReadString() {
164 161 JsonGrammar.TokenType tag;
165 162 m_tokenBuilder.Clear();
166 163
167 164 while (ReadStringChunk(m_stringContext, out tag)) {
168 165 switch (tag) {
169 166 case JsonGrammar.TokenType.StringBound:
170 167 m_tokenBuilder.Length--;
171 168 return m_tokenBuilder.ToString();
172 169 case JsonGrammar.TokenType.UnescapedChar:
173 170 break;
174 171 case JsonGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
175 172 m_tokenBuilder.CopyTo(m_tokenBuilder.Length - 4, m_unescapeBuf, 0, 4);
176 173 m_tokenBuilder.Length -= 6;
177 174 m_tokenBuilder.Append(StringTranslator.TranslateHexUnicode(m_unescapeBuf, 0));
178 175 break;
179 176 case JsonGrammar.TokenType.EscapedChar: // \t - escape sequence
180 177 var ch = m_tokenBuilder[m_tokenBuilder.Length-1];
181 178 m_tokenBuilder.Length -= 2;
182 179 m_tokenBuilder.Append(StringTranslator.TranslateEscapedChar(ch));
183 180 break;
184 181 }
185 182 }
186 183
187 184 throw new ParserException("Unexpected end of data");
188 185 }
189 186 }
190 187 }
@@ -1,70 +1,66
1 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 2
7 3 namespace Implab.Formats.Json {
8 4 public class JsonStringScanner : JsonScanner {
9 5 const int _defaultBuffer = 64;
10 6
11 7 readonly string m_data;
12 8 int m_offset;
13 9
14 10 JsonStringScanner(string data, char[] buffer, int pos, int length, int offset) : base(buffer, pos, length) {
15 11 m_data = data;
16 12 m_offset = offset;
17 13 }
18 14
19 15 protected override int Read(char[] buffer, int offset, int size) {
20 16 if (m_data == null)
21 17 return 0;
22 18 if (m_offset >= m_data.Length)
23 19 return 0;
24 20
25 21 var count = Math.Min(size, m_data.Length - m_offset);
26 22
27 23 m_data.CopyTo(m_offset, buffer, offset, count);
28 24 m_offset += count;
29 25
30 26 return count;
31 27 }
32 28
33 29 public static JsonStringScanner Create(string data) {
34 30 Safe.ArgumentNotNull(data, nameof(data));
35 31
36 32 if (data.Length <= _defaultBuffer)
37 33 return new JsonStringScanner(null, data.ToCharArray(), 0, data.Length, data.Length);
38 34
39 35 var buffer = new char[_defaultBuffer];
40 36 data.CopyTo(0, buffer, 0, _defaultBuffer);
41 37 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, _defaultBuffer);
42 38 }
43 39
44 40 public static JsonStringScanner Create(string data, int offset, int length) {
45 41 Safe.ArgumentNotNull(data, nameof(data));
46 42 Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset));
47 43 Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length));
48 44
49 45 if (length <= _defaultBuffer) {
50 46 var buffer = new char[length];
51 47 data.CopyTo(offset, buffer, 0, length);
52 48
53 49 return new JsonStringScanner(null, buffer, 0, length, length);
54 50 } else {
55 51 var buffer = new char[_defaultBuffer];
56 52 data.CopyTo(offset, buffer, 0, _defaultBuffer);
57 53 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, offset + _defaultBuffer);
58 54 }
59 55 }
60 56
61 57 public static JsonStringScanner Create(char[] data, int offset, int length) {
62 58 Safe.ArgumentNotNull(data, nameof(data));
63 59 Safe.ArgumentInRange(offset >= 0 && offset < data.Length , nameof(offset));
64 60 Safe.ArgumentInRange(length >= 0 && offset + length <= data.Length, nameof(length));
65 61
66 62 return new JsonStringScanner(null, data, offset, offset + length, offset + length);
67 63
68 64 }
69 65 }
70 66 }
@@ -1,49 +1,45
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
1 using System.IO;
5 2 using System.Text;
6 using System.Threading.Tasks;
7 3
8 4 namespace Implab.Formats.Json {
9 5 public class JsonTextScanner : JsonScanner {
10 6 const int _bufferSize = 16*4096;
11 7 readonly TextReader m_reader;
12 8
13 9 JsonTextScanner(TextReader reader, char[] buffer) : base(buffer, 0, 0) {
14 10 m_reader = reader;
15 11 }
16 12
17 13 protected override int Read(char[] buffer, int offset, int size) {
18 14 return m_reader.Read(buffer, offset, size);
19 15 }
20 16
21 17 public static JsonTextScanner Create(string file, Encoding encoding) {
22 18 return new JsonTextScanner(new StreamReader(file, encoding), new char[_bufferSize]);
23 19 }
24 20
25 21 public static JsonTextScanner Create(string file) {
26 22 return new JsonTextScanner(new StreamReader(file), new char[_bufferSize]);
27 23 }
28 24
29 25 public static JsonTextScanner Create(Stream stream, Encoding encoding) {
30 26 return new JsonTextScanner(new StreamReader(stream, encoding), new char[_bufferSize]);
31 27 }
32 28
33 29 public static JsonTextScanner Create(Stream stream) {
34 30 return new JsonTextScanner(new StreamReader(stream), new char[_bufferSize]);
35 31 }
36 32
37 33 public static JsonTextScanner Create(TextReader reader) {
38 34 Safe.ArgumentNotNull(reader, nameof(reader));
39 35 return new JsonTextScanner(reader, new char[_bufferSize]);
40 36 }
41 37
42 38 protected override void Dispose(bool disposing) {
43 39 if (disposing)
44 40 Safe.Dispose(m_reader);
45 41
46 42 base.Dispose(disposing);
47 43 }
48 44 }
49 45 }
@@ -1,52 +1,46
1 using Implab;
2 using Implab.Formats;
3 using System;
4 using System.Collections.Generic;
5 using System.Diagnostics;
1 using System.Diagnostics;
6 2 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 3
10 4 namespace Implab.Formats.Json {
11 5 /// <summary>
12 6 /// Класс для прСобразования экранированной строки JSON
13 7 /// </summary>
14 8 static class StringTranslator {
15 9 static readonly char[] _escMap;
16 10 static readonly int[] _hexMap;
17 11
18 12 static StringTranslator() {
19 13 var chars = new char[] { 'b', 'f', 't', 'r', 'n', '\\', '/', '"' };
20 14 var vals = new char[] { '\b', '\f', '\t', '\r', '\n', '\\', '/', '"' };
21 15
22 16 _escMap = new char[chars.Max() + 1];
23 17
24 18 for (int i = 0; i < chars.Length; i++)
25 19 _escMap[chars[i]] = vals[i];
26 20
27 21 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 22 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 23
30 24 _hexMap = new int[hexs.Max() + 1];
31 25
32 26 for (int i = 0; i < hexs.Length; i++)
33 27 _hexMap[hexs[i]] = ints[i];
34 28
35 29 }
36 30
37 31 internal static char TranslateEscapedChar(char symbol) {
38 32 return _escMap[symbol];
39 33 }
40 34
41 35 internal static char TranslateHexUnicode(char[] symbols, int offset) {
42 36 Debug.Assert(symbols != null);
43 37 Debug.Assert(symbols.Length - offset >= 4);
44 38
45 39 int value = (_hexMap[symbols[offset]] << 12)
46 40 | (_hexMap[symbols[offset + 1]] << 8)
47 41 | (_hexMap[symbols[offset + 2]] << 4)
48 42 | (_hexMap[symbols[offset + 3]]);
49 43 return (char)value;
50 44 }
51 45 }
52 46 }
@@ -1,45 +1,42
1 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 2
6 3 namespace Implab {
7 4 public interface IPromise {
8 5
9 6 /// <summary>
10 7 /// Π’ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ Ρ‡Π΅Ρ€Π΅Π· Π΄Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.
11 8 /// </summary>
12 9 Type ResultType { get; }
13 10
14 11 /// <summary>
15 12 /// ΠžΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ являСтся Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ΠΌ, Π»ΠΈΠ±ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ, Π»ΠΈΠ±ΠΎ с ошибкой, Π»ΠΈΠ±ΠΎ ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ.
16 13 /// </summary>
17 14 bool IsResolved { get; }
18 15
19 16 bool IsRejected { get; }
20 17
21 18 bool IsFulfilled { get; }
22 19
23 20 /// <summary>
24 21 /// Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ выполнСния обСщания, Π»ΠΈΠ±ΠΎ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π° ΠΎΡ‚ΠΌΠ΅Π½Ρ‹.
25 22 /// </summary>
26 23 Exception RejectReason { get; }
27 24
28 25 /// <summary>
29 26 /// Adds specified listeners to the current promise.
30 27 /// </summary>
31 28 /// <param name="success">The handler called on the successful promise completion.</param>
32 29 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
33 30 /// <returns>The current promise.</returns>
34 31 void Then(IResolvable next);
35 32
36 33 /// <summary>
37 34 /// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ обСщания ΠΊ Π·Π°Π΄Π°Π½Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½ΠΎΠ²ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅.
38 35 /// </summary>
39 36 IPromise<T> Cast<T>();
40 37
41 38 void Join();
42 39
43 40 void Join(int timeout);
44 41 }
45 42 }
@@ -1,12 +1,10
1 using System;
2
3 namespace Implab {
1 namespace Implab {
4 2 public interface IPromise<out T> : IPromise {
5 3
6 4 void Then(IResolvable<T> next);
7 5
8 6 new T Join();
9 7
10 8 new T Join(int timeout);
11 9 }
12 10 }
@@ -1,563 +1,562
1 1 using System.Threading;
2 2 using System.Collections.Generic;
3 3 using System;
4 4 using System.Collections;
5 using System.Diagnostics;
6 5 using System.Runtime.CompilerServices;
7 6
8 7 namespace Implab.Parallels {
9 8 public class AsyncQueue<T> : IEnumerable<T> {
10 9 class Chunk {
11 10 public volatile Chunk next;
12 11
13 12 volatile int m_low;
14 13 volatile int m_hi;
15 14 volatile int m_alloc;
16 15 readonly int m_size;
17 16 readonly T[] m_data;
18 17
19 18 public Chunk(int size) {
20 19 m_size = size;
21 20 m_data = new T[size];
22 21 }
23 22
24 23 public Chunk(int size, T value) {
25 24 m_size = size;
26 25 m_hi = 1;
27 26 m_alloc = 1;
28 27 m_data = new T[size];
29 28 m_data[0] = value;
30 29 }
31 30
32 31 public Chunk(int size, int allocated) {
33 32 m_size = size;
34 33 m_hi = allocated;
35 34 m_alloc = allocated;
36 35 m_data = new T[size];
37 36 }
38 37
39 38 public void WriteData(T[] data, int offset, int dest, int length) {
40 39 Array.Copy(data, offset, m_data, dest, length);
41 40 }
42 41
43 42 public int Low {
44 43 get { return m_low; }
45 44 }
46 45
47 46 public int Hi {
48 47 get { return m_hi; }
49 48 }
50 49
51 50 public int Size {
52 51 get { return m_size; }
53 52 }
54 53
55 54 [MethodImpl(MethodImplOptions.AggressiveInlining)]
56 55 void AwaitWrites(int mark) {
57 56 if (m_hi != mark) {
58 57 SpinWait spin = new SpinWait();
59 58 do {
60 59 spin.SpinOnce();
61 60 } while (m_hi != mark);
62 61 }
63 62 }
64 63
65 64 public bool TryEnqueue(T value) {
66 65 int alloc;
67 66 do {
68 67 alloc = m_alloc;
69 68 if (alloc >= m_size)
70 69 return false;
71 70 } while(alloc != Interlocked.CompareExchange(ref m_alloc, alloc + 1, alloc));
72 71
73 72 m_data[alloc] = value;
74 73
75 74 AwaitWrites(alloc);
76 75 m_hi = alloc + 1;
77 76
78 77 return true;
79 78 }
80 79
81 80 /// <summary>
82 81 /// Prevents from allocating new space in the chunk and waits for all write operations to complete
83 82 /// </summary>
84 83 public void Seal() {
85 84 var actual = Math.Min(Interlocked.Exchange(ref m_alloc, m_size), m_size);
86 85 AwaitWrites(actual);
87 86 }
88 87
89 88 public bool TryDequeue(out T value, out bool recycle) {
90 89 int low;
91 90 do {
92 91 low = m_low;
93 92 if (low >= m_hi) {
94 93 value = default(T);
95 94 recycle = (low == m_size);
96 95 return false;
97 96 }
98 97 } while (low != Interlocked.CompareExchange(ref m_low, low + 1, low));
99 98
100 99 recycle = (low + 1 == m_size);
101 100 value = m_data[low];
102 101
103 102 return true;
104 103 }
105 104
106 105 public bool TryEnqueueBatch(T[] batch, int offset, int length, out int enqueued) {
107 106 int alloc;
108 107 do {
109 108 alloc = m_alloc;
110 109 if (alloc >= m_size) {
111 110 enqueued = 0;
112 111 return false;
113 112 } else {
114 113 enqueued = Math.Min(length, m_size - alloc);
115 114 }
116 115 } while (alloc != Interlocked.CompareExchange(ref m_alloc, alloc + enqueued, alloc));
117 116
118 117 Array.Copy(batch, offset, m_data, alloc, enqueued);
119 118
120 119 AwaitWrites(alloc);
121 120 m_hi = alloc + enqueued;
122 121 return true;
123 122 }
124 123
125 124 public bool TryDequeueBatch(T[] buffer, int offset, int length, out int dequeued, out bool recycle) {
126 125 int low, hi, batchSize;
127 126
128 127 do {
129 128 low = m_low;
130 129 hi = m_hi;
131 130 if (low >= hi) {
132 131 dequeued = 0;
133 132 recycle = (low == m_size);
134 133 return false;
135 134 }
136 135 batchSize = Math.Min(hi - low, length);
137 136 } while (low != Interlocked.CompareExchange(ref m_low, low + batchSize, low));
138 137
139 138 dequeued = batchSize;
140 139 recycle = (low + batchSize == m_size);
141 140 Array.Copy(m_data, low, buffer, offset, batchSize);
142 141
143 142 return true;
144 143 }
145 144
146 145 public T GetAt(int pos) {
147 146 return m_data[pos];
148 147 }
149 148 }
150 149
151 150 public const int DEFAULT_CHUNK_SIZE = 32;
152 151 public const int MAX_CHUNK_SIZE = 256;
153 152
154 153 Chunk m_first;
155 154 Chunk m_last;
156 155
157 156 public AsyncQueue() {
158 157 m_first = m_last = new Chunk(DEFAULT_CHUNK_SIZE);
159 158 }
160 159
161 160 /// <summary>
162 161 /// Adds the specified value to the queue.
163 162 /// </summary>
164 163 /// <param name="value">Tha value which will be added to the queue.</param>
165 164 public void Enqueue(T value) {
166 165 var last = m_last;
167 166 SpinWait spin = new SpinWait();
168 167 while (!last.TryEnqueue(value)) {
169 168 // try to extend queue
170 169 var chunk = new Chunk(DEFAULT_CHUNK_SIZE, value);
171 170 var t = Interlocked.CompareExchange(ref m_last, chunk, last);
172 171 if (t == last) {
173 172 last.next = chunk;
174 173 break;
175 174 } else {
176 175 last = t;
177 176 }
178 177 spin.SpinOnce();
179 178 }
180 179 }
181 180
182 181 /// <summary>
183 182 /// Adds the specified data to the queue.
184 183 /// </summary>
185 184 /// <param name="data">The buffer which contains the data to be enqueued.</param>
186 185 /// <param name="offset">The offset of the data in the buffer.</param>
187 186 /// <param name="length">The size of the data to read from the buffer.</param>
188 187 public void EnqueueRange(T[] data, int offset, int length) {
189 188 if (data == null)
190 189 throw new ArgumentNullException("data");
191 190 if (offset < 0)
192 191 throw new ArgumentOutOfRangeException("offset");
193 192 if (length < 1 || offset + length > data.Length)
194 193 throw new ArgumentOutOfRangeException("length");
195 194
196 195 while (length > 0) {
197 196 var last = m_last;
198 197 int enqueued;
199 198
200 199 if (last.TryEnqueueBatch(data, offset, length, out enqueued)) {
201 200 length -= enqueued;
202 201 offset += enqueued;
203 202 }
204 203
205 204 if (length > 0) {
206 205 // we have something to enqueue
207 206
208 207 var tail = length % MAX_CHUNK_SIZE;
209 208
210 209 var chunk = new Chunk(Math.Max(tail, DEFAULT_CHUNK_SIZE), tail);
211 210
212 211 if (last != Interlocked.CompareExchange(ref m_last, chunk, last))
213 212 continue; // we wasn't able to catch the writer, roundtrip
214 213
215 214 // we are lucky
216 215 // we can exclusively write our batch, the other writers will continue their work
217 216
218 217 length -= tail;
219 218
220 219
221 220 for(var i = 0; i < length; i+= MAX_CHUNK_SIZE) {
222 221 var node = new Chunk(MAX_CHUNK_SIZE, MAX_CHUNK_SIZE);
223 222 node.WriteData(data, offset, 0, MAX_CHUNK_SIZE);
224 223 offset += MAX_CHUNK_SIZE;
225 224 // fence last.next is volatile
226 225 last.next = node;
227 226 last = node;
228 227 }
229 228
230 229 if (tail > 0)
231 230 chunk.WriteData(data, offset, 0, tail);
232 231
233 232 // fence last.next is volatile
234 233 last.next = chunk;
235 234 return;
236 235 }
237 236 }
238 237 }
239 238
240 239 /// <summary>
241 240 /// Tries to retrieve the first element from the queue.
242 241 /// </summary>
243 242 /// <returns><c>true</c>, if element is dequeued, <c>false</c> otherwise.</returns>
244 243 /// <param name="value">The value of the dequeued element.</param>
245 244 public bool TryDequeue(out T value) {
246 245 var chunk = m_first;
247 246 do {
248 247 bool recycle;
249 248
250 249 var result = chunk.TryDequeue(out value, out recycle);
251 250
252 251 if (recycle && chunk.next != null) {
253 252 // this chunk is waste
254 253 chunk = Interlocked.CompareExchange(ref m_first, chunk.next, chunk);
255 254 } else {
256 255 return result; // this chunk is usable and returned actual result
257 256 }
258 257
259 258 if (result) // this chunk is waste but the true result is always actual
260 259 return true;
261 260 } while (true);
262 261 }
263 262
264 263 /// <summary>
265 264 /// Tries to dequeue the specified amount of data from the queue.
266 265 /// </summary>
267 266 /// <returns><c>true</c>, if data was deuqueued, <c>false</c> otherwise.</returns>
268 267 /// <param name="buffer">The buffer to which the data will be written.</param>
269 268 /// <param name="offset">The offset in the buffer at which the data will be written.</param>
270 269 /// <param name="length">The maximum amount of data to be retrieved.</param>
271 270 /// <param name="dequeued">The actual amout of the retrieved data.</param>
272 271 public bool TryDequeueRange(T[] buffer, int offset, int length, out int dequeued) {
273 272 if (buffer == null)
274 273 throw new ArgumentNullException("buffer");
275 274 if (offset < 0)
276 275 throw new ArgumentOutOfRangeException("offset");
277 276 if (length < 1 || offset + length > buffer.Length)
278 277 throw new ArgumentOutOfRangeException("length");
279 278
280 279 var chunk = m_first;
281 280 dequeued = 0;
282 281 do {
283 282 bool recycle;
284 283 int actual;
285 284 if (chunk.TryDequeueBatch(buffer, offset, length, out actual, out recycle)) {
286 285 offset += actual;
287 286 length -= actual;
288 287 dequeued += actual;
289 288 }
290 289
291 290 if (recycle && chunk.next != null) {
292 291 // this chunk is waste
293 292 chunk = Interlocked.CompareExchange(ref m_first, chunk.next, chunk);
294 293 } else {
295 294 chunk = null;
296 295 }
297 296
298 297 if (length == 0)
299 298 return true;
300 299 } while (chunk != null);
301 300
302 301 return dequeued != 0;
303 302 }
304 303
305 304 /// <summary>
306 305 /// Tries to dequeue all remaining data in the first chunk.
307 306 /// </summary>
308 307 /// <returns><c>true</c>, if data was dequeued, <c>false</c> otherwise.</returns>
309 308 /// <param name="buffer">The buffer to which the data will be written.</param>
310 309 /// <param name="offset">The offset in the buffer at which the data will be written.</param>
311 310 /// <param name="length">Tha maximum amount of the data to be dequeued.</param>
312 311 /// <param name="dequeued">The actual amount of the dequeued data.</param>
313 312 public bool TryDequeueChunk(T[] buffer, int offset, int length, out int dequeued) {
314 313 if (buffer == null)
315 314 throw new ArgumentNullException("buffer");
316 315 if (offset < 0)
317 316 throw new ArgumentOutOfRangeException("offset");
318 317 if (length < 1 || offset + length > buffer.Length)
319 318 throw new ArgumentOutOfRangeException("length");
320 319
321 320 var chunk = m_first;
322 321 do {
323 322 bool recycle;
324 323 chunk.TryDequeueBatch(buffer, offset, length, out dequeued, out recycle);
325 324
326 325 if (recycle && chunk.next != null) {
327 326 // this chunk is waste
328 327 chunk = Interlocked.CompareExchange(ref m_first, chunk.next, chunk);
329 328 } else {
330 329 chunk = null;
331 330 }
332 331
333 332 // if we have dequeued any data, then return
334 333 if (dequeued != 0)
335 334 return true;
336 335
337 336 } while (chunk != null);
338 337
339 338 return false;
340 339 }
341 340
342 341
343 342 public void Clear() {
344 343 // start the new queue
345 344 var chunk = new Chunk(DEFAULT_CHUNK_SIZE);
346 345 do {
347 346 var first = m_first;
348 347 if (first.next == null && first != m_last) {
349 348 continue;
350 349 }
351 350
352 351 // here we will create inconsistency which will force others to spin
353 352 // and prevent from fetching. chunk.next = null
354 353 if (first != Interlocked.CompareExchange(ref m_first, chunk, first))
355 354 continue;// inconsistent
356 355
357 356 m_last = chunk;
358 357 return;
359 358 } while (true);
360 359 }
361 360
362 361 public List<T> Drain() {
363 362 Chunk chunk = null;
364 363 do {
365 364 var first = m_first;
366 365 // first.next is volatile
367 366 if (first.next == null) {
368 367 if (first != m_last)
369 368 continue;
370 369 else if (first.Hi == first.Low)
371 370 return new List<T>();
372 371 }
373 372
374 373 // start the new queue
375 374 if (chunk == null)
376 375 chunk = new Chunk(DEFAULT_CHUNK_SIZE);
377 376
378 377 // here we will create inconsistency which will force others to spin
379 378 // and prevent from fetching. chunk.next = null
380 379 if (first != Interlocked.CompareExchange(ref m_first, chunk, first))
381 380 continue;// inconsistent
382 381
383 382 var last = Interlocked.Exchange(ref m_last, chunk);
384 383
385 384 return ReadChunks(first, last);
386 385
387 386 } while (true);
388 387 }
389 388
390 389 static List<T> ReadChunks(Chunk chunk, object last) {
391 390 var result = new List<T>();
392 391 var buffer = new T[MAX_CHUNK_SIZE];
393 392 int actual;
394 393 bool recycle;
395 394 SpinWait spin = new SpinWait();
396 395 while (chunk != null) {
397 396 // ensure all write operations on the chunk are complete
398 397 chunk.Seal();
399 398
400 399 // we need to read the chunk using this way
401 400 // since some client still may completing the dequeue
402 401 // operation, such clients most likely won't get results
403 402 while (chunk.TryDequeueBatch(buffer, 0, buffer.Length, out actual, out recycle))
404 403 result.AddRange(new ArraySegmentCollection(buffer, 0, actual));
405 404
406 405 if (chunk == last) {
407 406 chunk = null;
408 407 } else {
409 408 while (chunk.next == null)
410 409 spin.SpinOnce();
411 410 chunk = chunk.next;
412 411 }
413 412 }
414 413
415 414 return result;
416 415 }
417 416
418 417 struct ArraySegmentCollection : ICollection<T> {
419 418 readonly T[] m_data;
420 419 readonly int m_offset;
421 420 readonly int m_length;
422 421
423 422 public ArraySegmentCollection(T[] data, int offset, int length) {
424 423 m_data = data;
425 424 m_offset = offset;
426 425 m_length = length;
427 426 }
428 427
429 428 #region ICollection implementation
430 429
431 430 public void Add(T item) {
432 431 throw new NotSupportedException();
433 432 }
434 433
435 434 public void Clear() {
436 435 throw new NotSupportedException();
437 436 }
438 437
439 438 public bool Contains(T item) {
440 439 return false;
441 440 }
442 441
443 442 public void CopyTo(T[] array, int arrayIndex) {
444 443 Array.Copy(m_data, m_offset, array, arrayIndex, m_length);
445 444 }
446 445
447 446 public bool Remove(T item) {
448 447 throw new NotSupportedException();
449 448 }
450 449
451 450 public int Count {
452 451 get {
453 452 return m_length;
454 453 }
455 454 }
456 455
457 456 public bool IsReadOnly {
458 457 get {
459 458 return true;
460 459 }
461 460 }
462 461
463 462 #endregion
464 463
465 464 #region IEnumerable implementation
466 465
467 466 public IEnumerator<T> GetEnumerator() {
468 467 for (int i = m_offset; i < m_length + m_offset; i++)
469 468 yield return m_data[i];
470 469 }
471 470
472 471 #endregion
473 472
474 473 #region IEnumerable implementation
475 474
476 475 IEnumerator IEnumerable.GetEnumerator() {
477 476 return GetEnumerator();
478 477 }
479 478
480 479 #endregion
481 480 }
482 481
483 482 #region IEnumerable implementation
484 483
485 484 class Enumerator : IEnumerator<T> {
486 485 Chunk m_current;
487 486 int m_pos = -1;
488 487
489 488 public Enumerator(Chunk fisrt) {
490 489 m_current = fisrt;
491 490 }
492 491
493 492 #region IEnumerator implementation
494 493
495 494 public bool MoveNext() {
496 495 if (m_current == null)
497 496 return false;
498 497
499 498 if (m_pos == -1)
500 499 m_pos = m_current.Low;
501 500 else
502 501 m_pos++;
503 502
504 503 if (m_pos == m_current.Hi) {
505 504
506 505 m_current = m_pos == m_current.Size ? m_current.next : null;
507 506
508 507 m_pos = 0;
509 508
510 509 if (m_current == null)
511 510 return false;
512 511 }
513 512
514 513 return true;
515 514 }
516 515
517 516 public void Reset() {
518 517 throw new NotSupportedException();
519 518 }
520 519
521 520 object IEnumerator.Current {
522 521 get {
523 522 return Current;
524 523 }
525 524 }
526 525
527 526 #endregion
528 527
529 528 #region IDisposable implementation
530 529
531 530 public void Dispose() {
532 531 }
533 532
534 533 #endregion
535 534
536 535 #region IEnumerator implementation
537 536
538 537 public T Current {
539 538 get {
540 539 if (m_pos == -1 || m_current == null)
541 540 throw new InvalidOperationException();
542 541 return m_current.GetAt(m_pos);
543 542 }
544 543 }
545 544
546 545 #endregion
547 546 }
548 547
549 548 public IEnumerator<T> GetEnumerator() {
550 549 return new Enumerator(m_first);
551 550 }
552 551
553 552 #endregion
554 553
555 554 #region IEnumerable implementation
556 555
557 556 IEnumerator IEnumerable.GetEnumerator() {
558 557 return GetEnumerator();
559 558 }
560 559
561 560 #endregion
562 561 }
563 562 }
@@ -1,202 +1,201
1 1 using System;
2 2 using System.Threading;
3 using System.Diagnostics;
4 3
5 4 namespace Implab.Parallels {
6 5 /// <summary>
7 6 /// Implements a lightweight mechanism to aquire a shared or an exclusive lock.
8 7 /// </summary>
9 8 public class SharedLock {
10 9 readonly object m_lock = new object();
11 10 // the count of locks currently acquired by clients
12 11 int m_locks;
13 12 // the count of pending requests for upgrade
14 13 int m_upgrades;
15 14 bool m_exclusive;
16 15
17 16 public bool LockExclusive(int timeout) {
18 17 lock (m_lock) {
19 18 var dt = timeout;
20 19 if (m_locks > m_upgrades) {
21 20 var t1 = Environment.TickCount;
22 21 do {
23 22 if (!Monitor.Wait(m_lock, timeout))
24 23 return false;
25 24
26 25 if (m_locks == m_upgrades)
27 26 break;
28 27
29 28 if (timeout > 0) {
30 29 dt = timeout - Environment.TickCount + t1;
31 30 if (dt < 0)
32 31 return false;
33 32 }
34 33 } while(true);
35 34 }
36 35 m_exclusive = true;
37 36 m_locks ++;
38 37 return true;
39 38 }
40 39 }
41 40
42 41 public void LockExclusive() {
43 42 lock (m_lock) {
44 43
45 44 while (m_locks > m_upgrades)
46 45 Monitor.Wait(m_lock);
47 46
48 47 m_exclusive = true;
49 48 m_locks ++;
50 49 }
51 50 }
52 51
53 52 /// <summary>
54 53 /// Acquires a shared lock.
55 54 /// </summary>
56 55 /// <returns><c>true</c>, if the shared lock was acquired, <c>false</c> if the specified timeout was expired.</returns>
57 56 /// <param name="timeout">Timeout.</param>
58 57 public bool LockShared(int timeout) {
59 58 lock (m_lock) {
60 59 if (!m_exclusive) {
61 60 m_locks++;
62 61 return true;
63 62 }
64 63
65 64 if (m_locks == m_upgrades) {
66 65 m_exclusive = false;
67 66 m_locks = 1;
68 67 return true;
69 68 }
70 69
71 70 var t1 = Environment.TickCount;
72 71 var dt = timeout;
73 72 do {
74 73 if (!Monitor.Wait(m_lock, dt))
75 74 return false;
76 75
77 76 if (m_locks == m_upgrades || !m_exclusive)
78 77 break;
79 78
80 79 if (timeout >= 0) {
81 80 dt = timeout - Environment.TickCount + t1;
82 81 if (dt < 0)
83 82 return false;
84 83 }
85 84 } while(true);
86 85
87 86 m_locks ++;
88 87 m_exclusive = false;
89 88 return true;
90 89 }
91 90 }
92 91
93 92 /// <summary>
94 93 /// Acquires the shared lock.
95 94 /// </summary>
96 95 public void LockShared() {
97 96 lock (m_lock) {
98 97 if (!m_exclusive) {
99 98 m_locks++;
100 99 } else if (m_locks == m_upgrades) {
101 100 m_exclusive = false;
102 101 m_locks++;
103 102 } else {
104 103 while (m_exclusive && m_locks > m_upgrades)
105 104 Monitor.Wait(m_lock);
106 105
107 106 m_locks++;
108 107 m_exclusive = false;
109 108 }
110 109 }
111 110 }
112 111
113 112 /// <summary>
114 113 /// Upgrades the current lock to exclusive level.
115 114 /// </summary>
116 115 /// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
117 116 public void Upgrade() {
118 117 lock (m_lock) {
119 118 if (!m_exclusive) {
120 119
121 120 if (m_locks <= m_upgrades)
122 121 throw new InvalidOperationException();
123 122
124 123 if (m_locks - m_upgrades == 1) {
125 124 m_exclusive = true;
126 125 } else {
127 126 m_upgrades++;
128 127
129 128 while (m_locks > m_upgrades)
130 129 Monitor.Wait(m_lock);
131 130
132 131 m_upgrades--;
133 132 m_exclusive = true;
134 133 }
135 134 }
136 135 }
137 136 }
138 137
139 138 /// <summary>
140 139 /// Upgrades the current lock to exclusive level.
141 140 /// </summary>
142 141 /// <param name="timeout">Timeout.</param>
143 142 /// <returns><c>true</c> if the current lock was updated, <c>false</c> the specified timeout was expired.</returns>
144 143 /// <remarks>If the current lock is exclusive already the method does nothing.</remarks>
145 144 public bool Upgrade(int timeout) {
146 145 lock (m_lock) {
147 146 if (m_exclusive)
148 147 return true;
149 148 if (m_locks <= m_upgrades)
150 149 throw new InvalidOperationException();
151 150
152 151 if (m_locks - m_upgrades == 1) {
153 152 m_exclusive = true;
154 153 } else {
155 154 var t1 = Environment.TickCount;
156 155 var dt = timeout;
157 156 m_upgrades++;
158 157 do {
159 158 if (!Monitor.Wait(m_lock, dt)) {
160 159 m_upgrades--;
161 160 return false;
162 161 }
163 162
164 163 // we may get there but the shared lock already aquired
165 164 if (m_locks == m_upgrades)
166 165 break;
167 166
168 167 if (timeout >= 0) {
169 168 dt = timeout - Environment.TickCount + t1;
170 169 if (dt < 0) {
171 170 m_upgrades--;
172 171 return false;
173 172 }
174 173 }
175 174 } while(true);
176 175 m_upgrades--;
177 176 m_exclusive = true;
178 177 }
179 178 return true;
180 179 }
181 180 }
182 181
183 182 /// <summary>
184 183 /// Downgrades this lock to shared level.
185 184 /// </summary>
186 185 public void Downgrade() {
187 186 lock (m_lock)
188 187 m_exclusive = false;
189 188 }
190 189
191 190 /// <summary>
192 191 /// Releases the current lock.
193 192 /// </summary>
194 193 public void Release() {
195 194 lock (m_lock)
196 195 // if no more running threads left
197 196 if (--m_locks == m_upgrades)
198 197 Monitor.PulseAll(m_lock);
199 198 }
200 199 }
201 200 }
202 201
@@ -1,31 +1,30
1 using System;
2 using System.Threading;
1 using System.Threading;
3 2
4 3 namespace Implab.Parallels {
5 4 /// <summary>
6 5 /// Implements a simple signalling logic using <see cref="Monitor.PulseAll(object)"/>.
7 6 /// </summary>
8 7 public class Signal {
9 8 readonly object m_lock = new object();
10 9 bool m_state;
11 10
12 11 public void Set() {
13 12 lock(m_lock) {
14 13 m_state = true;
15 14 Monitor.PulseAll(m_lock);
16 15 }
17 16 }
18 17
19 18 public void Wait() {
20 19 lock (m_lock)
21 20 if (!m_state)
22 21 Monitor.Wait(m_lock);
23 22 }
24 23
25 24 public bool Wait(int timeout) {
26 25 lock (m_lock)
27 26 return m_state || Monitor.Wait(m_lock, timeout);
28 27 }
29 28 }
30 29 }
31 30
@@ -1,115 +1,114
1 1 using System.Threading;
2 2 using System.Collections.Generic;
3 using System;
4 3 using System.Collections;
5 4
6 5 namespace Implab.Parallels {
7 6
8 7 /// <summary>
9 8 /// Very simple thred-safe FIFO queue based on the sinle linked list.
10 9 /// </summary>
11 10 /// <typeparam name="T"></typeparam>
12 11 /// <remarks>
13 12 /// This queue uses interlocked operations to add and remove nodes,
14 13 /// each node stores a single value. The queue provides mean performance,
15 14 /// moderate overhead and situable for a small amount of elements.
16 15 /// </remarks>
17 16 public class SimpleAsyncQueue<T> : IEnumerable<T> {
18 17 class Node {
19 18 public Node(T value) {
20 19 this.value = value;
21 20 }
22 21 public readonly T value;
23 22 public volatile Node next;
24 23 }
25 24
26 25 // the reader and the writer are maintained completely independent,
27 26 // the reader can read next item when m_first.next is not null
28 27 // the writer creates a new node, moves m_last to this node and
29 28 // only after that restores the reference from the previous node
30 29 // making the reader able to read the new node.
31 30
32 31 volatile Node m_first; // position on the node which is already read
33 32 volatile Node m_last; // position on the node which is already written
34 33
35 34 public SimpleAsyncQueue() {
36 35 m_first = m_last = new Node(default(T));
37 36 }
38 37
39 38 public void Enqueue(T value) {
40 39 var next = new Node(value);
41 40
42 // Interlocaked.CompareExchange implies Thread.MemoryBarrier();
41 // Interlocked.CompareExchange implies Thread.MemoryBarrier();
43 42 // to ensure that the next node is completely constructed
44 43 var last = Interlocked.Exchange(ref m_last, next);
45 44
46 45 // release-fence
47 46 last.next = next;
48 47
49 48 }
50 49
51 50 public bool TryDequeue(out T value) {
52 51 Node first = m_first;
53 52 Node next = first.next;
54 53
55 54 if (next == null) {
56 55 value = default(T);
57 56 return false;
58 57 }
59 58
60 59 var first2 = Interlocked.CompareExchange(ref m_first, next, first);
61 60
62 61 if (first != first2) {
63 62 // head is updated by someone else
64 63
65 64 SpinWait spin = new SpinWait();
66 65 do {
67 66 first = first2;
68 67 next = first.next;
69 68 if (next == null) {
70 69 value = default(T);
71 70 return false;
72 71 }
73 72
74 73 first2 = Interlocked.CompareExchange(ref m_first, next, first);
75 74 if (first == first2)
76 75 break;
77 76 spin.SpinOnce();
78 77 } while (true);
79 78 }
80 79
81 80 value = next.value;
82 81 return true;
83 82 }
84 83
85 84 /// <summary>
86 85 /// Creates a thin copy of the current linked list.
87 86 /// </summary>
88 87 /// <remarks>Iterating over the snapshot is thread safe and
89 88 /// will produce repeatble results. Each snapshot stores only
90 89 /// two references one for the first and one for last elements
91 90 /// from list.
92 91 /// <returns>Enumerable collection.</returns>
93 92 public IEnumerable<T> Snapshot() {
94 93 var first = m_first;
95 94 var last = m_last;
96 95
97 96 var current = m_first;
98 97 while(current != m_last) {
99 98 current = current.next;
100 99 yield return current.value;
101 100 }
102 101 }
103 102
104 103 public IEnumerator<T> GetEnumerator() {
105 104 for (var current = m_first.next; current != null; current = current.next) {
106 105 yield return current.value;
107 106 }
108 107 }
109 108
110 109 IEnumerator IEnumerable.GetEnumerator() {
111 110 return GetEnumerator();
112 111 }
113 112
114 113 }
115 114 }
@@ -1,222 +1,221
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Diagnostics;
4 4 using System.Reflection;
5 5 using System.Threading;
6 using System.Threading.Tasks;
7 6 using Implab.Parallels;
8 7
9 8 namespace Implab {
10 9 public class Promise : AbstractEvent<IResolvable>, IPromise {
11 10 public static IDispatcher DefaultDispatcher {
12 11 get {
13 12 return ThreadPoolDispatcher.Instance;
14 13 }
15 14 }
16 15
17 16 class ResolvableSignal : IResolvable {
18 17 public Signal Signal { get; private set; }
19 18 public ResolvableSignal() {
20 19 Signal = new Signal();
21 20 }
22 21
23 22
24 23 public void Reject(Exception error) {
25 24 Signal.Set();
26 25 }
27 26
28 27 public void Resolve() {
29 28 Signal.Set();
30 29 }
31 30 }
32 31
33 32 PromiseState m_state;
34 33
35 34 Exception m_error;
36 35
37 36 public bool IsRejected {
38 37 get {
39 38 return m_state == PromiseState.Rejected;
40 39 }
41 40 }
42 41
43 42 public bool IsFulfilled {
44 43 get {
45 44 return m_state == PromiseState.Fulfilled;
46 45 }
47 46 }
48 47
49 48 public Exception RejectReason {
50 49 get {
51 50 return m_error;
52 51 }
53 52 }
54 53
55 54 internal Promise() {
56 55
57 56 }
58 57
59 58 internal void ResolvePromise() {
60 59 if (BeginTransit()) {
61 60 m_state = PromiseState.Fulfilled;
62 61 CompleteTransit();
63 62 }
64 63 }
65 64
66 65 internal void RejectPromise(Exception reason) {
67 66 if (BeginTransit()) {
68 67 m_error = reason;
69 68 m_state = PromiseState.Rejected;
70 69 CompleteTransit();
71 70 }
72 71 }
73 72
74 73
75 74 #region implemented abstract members of AbstractPromise
76 75
77 76 protected override void SignalHandler(IResolvable handler) {
78 77 switch (m_state) {
79 78 case PromiseState.Fulfilled:
80 79 handler.Resolve();
81 80 break;
82 81 case PromiseState.Rejected:
83 82 handler.Reject(RejectReason);
84 83 break;
85 84 default:
86 85 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
87 86 }
88 87 }
89 88
90 89 protected void WaitResult(int timeout) {
91 90 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
92 91 throw new TimeoutException();
93 92 }
94 93
95 94 protected Signal GetFulfillSignal() {
96 95 var next = new ResolvableSignal();
97 96 Then(next);
98 97 return next.Signal;
99 98 }
100 99
101 100 #endregion
102 101
103 102
104 103 public Type ResultType {
105 104 get {
106 105 return typeof(void);
107 106 }
108 107 }
109 108
110 109
111 110 protected void Rethrow() {
112 111 Debug.Assert(m_error != null);
113 112 if (m_error is OperationCanceledException)
114 113 throw new OperationCanceledException("Operation cancelled", m_error);
115 114 else
116 115 throw new TargetInvocationException(m_error);
117 116 }
118 117
119 118 public void Then(IResolvable next) {
120 119 AddHandler(next);
121 120 }
122 121
123 122 public IPromise<T> Cast<T>() {
124 123 throw new InvalidCastException();
125 124 }
126 125
127 126 public void Join() {
128 127 WaitResult(-1);
129 128 if (IsRejected)
130 129 Rethrow();
131 130 }
132 131
133 132 public void Join(int timeout) {
134 133 WaitResult(timeout);
135 134 if (IsRejected)
136 135 Rethrow();
137 136 }
138 137
139 138 public static ResolvedPromise Resolve() {
140 139 return new ResolvedPromise();
141 140 }
142 141
143 142 public static ResolvedPromise<T> Resolve<T>(T result) {
144 143 return new ResolvedPromise<T>(result);
145 144 }
146 145
147 146 public static RejectedPromise Reject(Exception reason) {
148 147 return new RejectedPromise(reason);
149 148 }
150 149
151 150 public static RejectedPromise<T> Reject<T>(Exception reason) {
152 151 return new RejectedPromise<T>(reason);
153 152 }
154 153
155 154 public static IPromise Create(PromiseExecutor executor) {
156 155 return Create(executor, CancellationToken.None);
157 156 }
158 157
159 158 public static IPromise Create(PromiseExecutor executor, CancellationToken ct) {
160 159 Safe.ArgumentNotNull(executor, nameof(executor));
161 160 if (!ct.CanBeCanceled)
162 161 return Create(executor);
163 162
164 163 var d = new Deferred();
165 164
166 165 ct.Register(d.Cancel);
167 166
168 167 try {
169 168 if (!ct.IsCancellationRequested)
170 169 executor(d);
171 170 } catch(Exception e) {
172 171 d.Reject(e);
173 172 }
174 173 return d.Promise;
175 174 }
176 175
177 176 public static IPromise<T> Create<T>(PromiseExecutor<T> executor) {
178 177 return Create(executor, CancellationToken.None);
179 178 }
180 179
181 180 public static IPromise<T> Create<T>(PromiseExecutor<T> executor, CancellationToken ct) {
182 181 Safe.ArgumentNotNull(executor, nameof(executor));
183 182
184 183 var d = new Deferred<T>();
185 184
186 185 ct.Register(d.Cancel);
187 186
188 187 try {
189 188 if (!ct.IsCancellationRequested)
190 189 executor(d);
191 190 } catch(Exception e) {
192 191 d.Reject(e);
193 192 }
194 193 return d.Promise;
195 194 }
196 195
197 196 public static IPromise All(IEnumerable<IPromise> promises) {
198 197 var d = new Deferred();
199 198 var all = new PromiseAll(d);
200 199 foreach (var promise in promises) {
201 200 all.AddPromise(promise);
202 201 if (all.Done)
203 202 break;
204 203 }
205 204 all.Complete();
206 205 return all.ResultPromise;
207 206 }
208 207
209 208 public static IPromise<T[]> All<T>(IEnumerable<IPromise<T>> promises, Func<T, IPromise> cleanup = null, Action cancel = null) {
210 209 var d = new Deferred<T[]>();
211 210 var all = new PromiseAll<T>(d, cleanup, cancel);
212 211 foreach (var promise in promises) {
213 212 all.AddPromise(promise);
214 213 if (all.Done)
215 214 break;
216 215 }
217 216 all.Complete();
218 217 return all.ResultPromise;
219 218 }
220 219 }
221 220 }
222 221
@@ -1,92 +1,91
1 1 using System;
2 using System.Diagnostics;
3 2
4 3 namespace Implab {
5 4 class PromiseActionReaction : IResolvable {
6 5
7 6 readonly Deferred m_next;
8 7
9 8 readonly IDispatcher m_dispatcher;
10 9
11 10 readonly Action<Deferred> m_fulfilled;
12 11
13 12 readonly Action<Exception, Deferred> m_rejected;
14 13
15 14 public IPromise Promise {
16 15 get { return m_next.Promise; }
17 16 }
18 17
19 18 public PromiseActionReaction(Action<Deferred> fulfilled, Action<Exception, Deferred> rejected, Deferred next, IDispatcher dispatcher) {
20 19 m_next = next;
21 20 m_fulfilled = fulfilled;
22 21 m_rejected = rejected;
23 22 m_dispatcher = dispatcher;
24 23 }
25 24
26 25 public void Resolve() {
27 26 if (m_fulfilled != null) {
28 27 if (m_dispatcher != null)
29 28 m_dispatcher.Enqueue(ResolveImpl);
30 29 else
31 30 ResolveImpl();
32 31 } else {
33 32 m_next.Resolve();
34 33 }
35 34 }
36 35
37 36 void ResolveImpl() {
38 37 m_fulfilled(m_next);
39 38 }
40 39
41 40 public void Reject(Exception error) {
42 if (m_fulfilled != null) {
41 if (m_rejected != null) {
43 42 if (m_dispatcher != null)
44 43 m_dispatcher.Enqueue(RejectImpl, error);
45 44 else
46 45 RejectImpl(error);
47 46 } else {
48 47 m_next.Reject(error);
49 48 }
50 49 }
51 50
52 51 void RejectImpl(Exception error) {
53 52 m_rejected(error, m_next);
54 53 }
55 54
56 55 public static PromiseActionReaction Create(Action fulfilled, Action<Exception> rejected, IDispatcher dispatcher) {
57 56 return new PromiseActionReaction(
58 57 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
59 58 rejected != null ? PromiseHandler.Create(rejected) : null,
60 59 new Deferred(),
61 60 dispatcher
62 61 );
63 62 }
64 63
65 64 public static PromiseActionReaction Create(Func<IPromise> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) {
66 65 return new PromiseActionReaction(
67 66 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
68 67 rejected != null ? PromiseHandler.Create(rejected) : null,
69 68 new Deferred(),
70 69 dispatcher
71 70 );
72 71 }
73 72
74 73 public static PromiseActionReaction Create(Action fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) {
75 74 return new PromiseActionReaction(
76 75 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
77 76 rejected != null ? PromiseHandler.Create(rejected) : null,
78 77 new Deferred(),
79 78 dispatcher
80 79 );
81 80 }
82 81
83 82 public static PromiseActionReaction Create(Func<IPromise> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) {
84 83 return new PromiseActionReaction(
85 84 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
86 85 rejected != null ? PromiseHandler.Create(rejected) : null,
87 86 new Deferred(),
88 87 dispatcher
89 88 );
90 89 }
91 90 }
92 91 } No newline at end of file
@@ -1,91 +1,90
1 1 using System;
2 using System.Diagnostics;
3 2
4 3 namespace Implab {
5 4 class PromiseActionReaction<T> : IResolvable<T> {
6 5 readonly Deferred m_next;
7 6
8 7 readonly IDispatcher m_dispatcher;
9 8
10 9 readonly Action<T, Deferred> m_fulfilled;
11 10
12 11 readonly Action<Exception, Deferred> m_rejected;
13 12
14 13 public IPromise Promise {
15 14 get { return m_next.Promise; }
16 15 }
17 16
18 17 public PromiseActionReaction(Action<T, Deferred> fulfilled, Action<Exception, Deferred> rejected, Deferred next, IDispatcher dispatcher) {
19 18 m_next = next;
20 19 m_fulfilled = fulfilled;
21 20 m_rejected = rejected;
22 21 m_dispatcher = dispatcher;
23 22 }
24 23
25 24 public void Resolve(T result) {
26 25 if (m_fulfilled != null) {
27 26 if (m_dispatcher != null)
28 27 m_dispatcher.Enqueue(ResolveImpl, result);
29 28 else
30 29 ResolveImpl(result);
31 30 } else {
32 31 m_next.Resolve();
33 32 }
34 33 }
35 34
36 35 void ResolveImpl (T result) {
37 36 m_fulfilled(result, m_next);
38 37 }
39 38
40 39 public void Reject(Exception error) {
41 if (m_fulfilled != null) {
40 if (m_rejected != null) {
42 41 if (m_dispatcher != null)
43 42 m_dispatcher.Enqueue(RejectImpl, error);
44 43 else
45 44 RejectImpl(error);
46 45 } else {
47 46 m_next.Reject(error);
48 47 }
49 48 }
50 49
51 50 void RejectImpl(Exception error) {
52 51 m_rejected(error, m_next);
53 52 }
54 53
55 54 public static PromiseActionReaction<T> Create(Action<T> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) {
56 55 return new PromiseActionReaction<T>(
57 56 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
58 57 rejected != null ? PromiseHandler.Create(rejected) : null,
59 58 new Deferred(),
60 59 dispatcher
61 60 );
62 61 }
63 62
64 63 public static PromiseActionReaction<T> Create(Func<T,IPromise> fulfilled, Action<Exception> rejected, IDispatcher dispatcher) {
65 64 return new PromiseActionReaction<T>(
66 65 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
67 66 rejected != null ? PromiseHandler.Create(rejected) : null,
68 67 new Deferred(),
69 68 dispatcher
70 69 );
71 70 }
72 71
73 72 public static PromiseActionReaction<T> Create(Action<T> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) {
74 73 return new PromiseActionReaction<T>(
75 74 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
76 75 rejected != null ? PromiseHandler.Create(rejected) : null,
77 76 new Deferred(),
78 77 dispatcher
79 78 );
80 79 }
81 80
82 81 public static PromiseActionReaction<T> Create(Func<T,IPromise> fulfilled, Func<Exception, IPromise> rejected, IDispatcher dispatcher) {
83 82 return new PromiseActionReaction<T>(
84 83 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
85 84 rejected != null ? PromiseHandler.Create(rejected) : null,
86 85 new Deferred(),
87 86 dispatcher
88 87 );
89 88 }
90 89 }
91 90 } No newline at end of file
@@ -1,226 +1,222
1 using System.Threading;
2 using System;
3 using Implab.Diagnostics;
4 using System.Collections.Generic;
5 using System.Linq;
1 using System;
6 2
7 3 namespace Implab {
8 4 public static class PromiseExtensions {
9 5
10 6 public static IPromise Then(this IPromise that, Action fulfilled, Action<Exception> rejected) {
11 7 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
12 8 that.Then(reaction);
13 9 return reaction.Promise;
14 10 }
15 11
16 12 public static IPromise Then(this IPromise that, Action fulfilled) {
17 13 var reaction = PromiseActionReaction.Create(fulfilled, null, Promise.DefaultDispatcher);
18 14 that.Then(reaction);
19 15 return reaction.Promise;
20 16 }
21 17
22 18 public static IPromise Then(this IPromise that, Action fulfilled, Func<Exception, IPromise> rejected) {
23 19 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
24 20 that.Then(reaction);
25 21 return reaction.Promise;
26 22 }
27 23
28 24 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Action<Exception> rejected) {
29 25 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
30 26 that.Then(reaction);
31 27 return reaction.Promise;
32 28 }
33 29
34 30 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled) {
35 31 var reaction = PromiseActionReaction.Create(fulfilled, null, Promise.DefaultDispatcher);
36 32 that.Then(reaction);
37 33 return reaction.Promise;
38 34 }
39 35
40 36 public static IPromise Then(this IPromise that, Func<IPromise> fulfilled, Func<Exception, IPromise> rejected) {
41 37 var reaction = PromiseActionReaction.Create(fulfilled, rejected, Promise.DefaultDispatcher);
42 38 that.Then(reaction);
43 39 return reaction.Promise;
44 40 }
45 41
46 42 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Action<Exception> rejected) {
47 43 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
48 44 that.Then(reaction);
49 45 return reaction.Promise;
50 46 }
51 47
52 48 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled) {
53 49 var reaction = PromiseActionReaction<T>.Create(fulfilled, null, Promise.DefaultDispatcher);
54 50 that.Then(reaction);
55 51 return reaction.Promise;
56 52 }
57 53
58 54 public static IPromise Then<T>(this IPromise<T> that, Action<T> fulfilled, Func<Exception, IPromise> rejected) {
59 55 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
60 56 that.Then(reaction);
61 57 return reaction.Promise;
62 58 }
63 59
64 60 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Action<Exception> rejected) {
65 61 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
66 62 that.Then(reaction);
67 63 return reaction.Promise;
68 64 }
69 65
70 66 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled) {
71 67 var reaction = PromiseActionReaction<T>.Create(fulfilled, null, Promise.DefaultDispatcher);
72 68 that.Then(reaction);
73 69 return reaction.Promise;
74 70 }
75 71
76 72 public static IPromise Then<T>(this IPromise<T> that, Func<T, IPromise> fulfilled, Func<Exception, IPromise> rejected) {
77 73 var reaction = PromiseActionReaction<T>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
78 74 that.Then(reaction);
79 75 return reaction.Promise;
80 76 }
81 77
82 78 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, Tout> rejected) {
83 79 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
84 80 that.Then(reaction);
85 81 return reaction.Promise;
86 82 }
87 83
88 84 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled) {
89 85 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
90 86 that.Then(reaction);
91 87 return reaction.Promise;
92 88 }
93 89
94 90 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
95 91 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
96 92 that.Then(reaction);
97 93 return reaction.Promise;
98 94 }
99 95
100 96 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
101 97 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
102 98 that.Then(reaction);
103 99 return reaction.Promise;
104 100 }
105 101
106 102 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled) {
107 103 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
108 104 that.Then(reaction);
109 105 return reaction.Promise;
110 106 }
111 107
112 108 public static IPromise<Tout> Then<Tout>(this IPromise that, Func<IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
113 109 var reaction = PromiseFuncReaction<Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
114 110 that.Then(reaction);
115 111 return reaction.Promise;
116 112 }
117 113
118 114 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, Tout> rejected) {
119 115 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
120 116 that.Then(reaction);
121 117 return reaction.Promise;
122 118 }
123 119
124 120 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled) {
125 121 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
126 122 that.Then(reaction);
127 123 return reaction.Promise;
128 124 }
129 125
130 126 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, Tout> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
131 127 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
132 128 that.Then(reaction);
133 129 return reaction.Promise;
134 130 }
135 131
136 132 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, Tout> rejected) {
137 133 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
138 134 that.Then(reaction);
139 135 return reaction.Promise;
140 136 }
141 137
142 138 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled) {
143 139 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, (Func<Exception, Tout>)null, Promise.DefaultDispatcher);
144 140 that.Then(reaction);
145 141 return reaction.Promise;
146 142 }
147 143
148 144 public static IPromise<Tout> Then<Tin, Tout>(this IPromise<Tin> that, Func<Tin, IPromise<Tout>> fulfilled, Func<Exception, IPromise<Tout>> rejected) {
149 145 var reaction = PromiseFuncReaction<Tin, Tout>.Create(fulfilled, rejected, Promise.DefaultDispatcher);
150 146 that.Then(reaction);
151 147 return reaction.Promise;
152 148 }
153 149
154 150 public static IPromise Catch(this IPromise that, Action<Exception> rejected) {
155 151 return Then(that, null, rejected);
156 152 }
157 153
158 154 public static IPromise Catch(this IPromise that, Func<Exception, IPromise> rejected) {
159 155 return Then(that, null, rejected);
160 156 }
161 157
162 158 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, Tout> rejected) {
163 159 return Then(that, (Func<Tout>)null, rejected);
164 160 }
165 161
166 162 public static IPromise<Tout> Catch<Tout>(this IPromise that, Func<Exception, IPromise<Tout>> rejected) {
167 163 return Then(that, (Func<Tout>)null, rejected);
168 164 }
169 165
170 166 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, Tout> rejected) {
171 167 return Then(that, (Func<Tin, Tout>)null, rejected);
172 168 }
173 169
174 170 public static IPromise<Tout> Catch<Tin, Tout>(this IPromise<Tin> that, Func<Exception, IPromise<Tout>> rejected) {
175 171 return Then(that, (Func<Tin, Tout>)null, rejected);
176 172 }
177 173
178 174 public static IPromise Finally(this IPromise that, Action final) {
179 175 return Then(that, final, e => {
180 176 final();
181 177 throw e.Rethrow();
182 178 });
183 179 }
184 180
185 181 public static IPromise Finally(this IPromise that, Func<IPromise> final) {
186 182 return Then(that, final, e => {
187 183 final();
188 184 throw e.Rethrow();
189 185 });
190 186 }
191 187
192 188 public static IPromise<T> Finally<T>(this IPromise<T> that, Action final) {
193 189 return Then<T, T>(that, x => {
194 190 final();
195 191 return x;
196 192 }, new Func<Exception, T>(e => {
197 193 final();
198 194 throw e.Rethrow();
199 195 }));
200 196 }
201 197
202 198 public static IPromise<T> Finally<T>(this IPromise<T> that, Func<IPromise> final) {
203 199 return Then<T, T>(that, x => {
204 200 return final()
205 201 .Then(() => x);
206 202 }, new Func<Exception, IPromise<T>>(e => {
207 203 return final()
208 204 .Then(new Func<T>(() => {
209 205 throw e.Rethrow();
210 206 }));
211 207 }));
212 208 }
213 209
214 210 public static PromiseAwaiter GetAwaiter(this IPromise that) {
215 211 Safe.ArgumentNotNull(that, nameof(that));
216 212 return new PromiseAwaiter(that);
217 213 }
218 214
219 215 public static PromiseAwaiter<T> GetAwaiter<T>(this IPromise<T> that) {
220 216 Safe.ArgumentNotNull(that, nameof(that));
221 217 return new PromiseAwaiter<T>(that);
222 218 }
223 219
224 220 }
225 221 }
226 222
@@ -1,91 +1,90
1 1 using System;
2 using System.Diagnostics;
3 2
4 3 namespace Implab {
5 4 class PromiseFuncReaction<TRet> : IResolvable {
6 5 readonly Deferred<TRet> m_next;
7 6
8 7 readonly IDispatcher m_dispatcher;
9 8
10 9 readonly Action<Deferred<TRet>> m_fulfilled;
11 10
12 11 readonly Action<Exception, Deferred<TRet>> m_rejected;
13 12
14 13 public IPromise<TRet> Promise {
15 14 get { return m_next.Promise; }
16 15 }
17 16
18 17 public PromiseFuncReaction(Action<Deferred<TRet>> fulfilled, Action<Exception, Deferred<TRet>> rejected, Deferred<TRet> next, IDispatcher dispatcher) {
19 18 m_next = next;
20 19 m_fulfilled = fulfilled;
21 20 m_rejected = rejected;
22 21 m_dispatcher = dispatcher;
23 22 }
24 23
25 24 public void Resolve() {
26 25 if (m_fulfilled != null) {
27 26 if (m_dispatcher != null)
28 27 m_dispatcher.Enqueue(ResolveImpl);
29 28 else
30 29 ResolveImpl();
31 30 } else {
32 31 m_next.Resolve(default(TRet));
33 32 }
34 33 }
35 34
36 35 void ResolveImpl () {
37 36 m_fulfilled(m_next);
38 37 }
39 38
40 39 public void Reject(Exception error) {
41 if (m_fulfilled != null) {
40 if (m_rejected != null) {
42 41 if (m_dispatcher != null)
43 42 m_dispatcher.Enqueue(RejectImpl, error);
44 43 else
45 44 RejectImpl(error);
46 45 } else {
47 46 m_next.Reject(error);
48 47 }
49 48 }
50 49
51 50 void RejectImpl(Exception error) {
52 51 m_rejected(error, m_next);
53 52 }
54 53
55 54 public static PromiseFuncReaction<TRet> Create(Func<TRet> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) {
56 55 return new PromiseFuncReaction<TRet>(
57 56 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
58 57 rejected != null ? PromiseHandler.Create(rejected) : null,
59 58 new Deferred<TRet>(),
60 59 dispatcher
61 60 );
62 61 }
63 62
64 63 public static PromiseFuncReaction<TRet> Create(Func<IPromise<TRet>> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) {
65 64 return new PromiseFuncReaction<TRet>(
66 65 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
67 66 rejected != null ? PromiseHandler.Create(rejected) : null,
68 67 new Deferred<TRet>(),
69 68 dispatcher
70 69 );
71 70 }
72 71
73 72 public static PromiseFuncReaction<TRet> Create(Func<TRet> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) {
74 73 return new PromiseFuncReaction<TRet>(
75 74 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
76 75 rejected != null ? PromiseHandler.Create(rejected) : null,
77 76 new Deferred<TRet>(),
78 77 dispatcher
79 78 );
80 79 }
81 80
82 81 public static PromiseFuncReaction<TRet> Create(Func<IPromise<TRet>> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) {
83 82 return new PromiseFuncReaction<TRet>(
84 83 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
85 84 rejected != null ? PromiseHandler.Create(rejected) : null,
86 85 new Deferred<TRet>(),
87 86 dispatcher
88 87 );
89 88 }
90 89 }
91 90 } No newline at end of file
@@ -1,97 +1,96
1 1 using System;
2 using System.Diagnostics;
3 2
4 3 namespace Implab {
5 4 class PromiseFuncReaction<TIn, TRet> : IResolvable<TIn> {
6 5 readonly Deferred<TRet> m_next;
7 6
8 7 readonly IDispatcher m_dispatcher;
9 8
10 9 readonly Action<TIn, Deferred<TRet>> m_fulfilled;
11 10
12 11 readonly Action<Exception, Deferred<TRet>> m_rejected;
13 12
14 13 public IPromise<TRet> Promise {
15 14 get { return m_next.Promise; }
16 15 }
17 16
18 17 public PromiseFuncReaction(Action<TIn, Deferred<TRet>> fulfilled, Action<Exception, Deferred<TRet>> rejected, Deferred<TRet> next, IDispatcher dispatcher) {
19 18 m_next = next;
20 19 m_fulfilled = fulfilled;
21 20 m_rejected = rejected;
22 21 m_dispatcher = dispatcher;
23 22 }
24 23
25 24 public void Resolve(TIn result) {
26 25 if (m_fulfilled != null) {
27 26 if (m_dispatcher != null)
28 27 m_dispatcher.Enqueue(ResolveImpl, result);
29 28 else
30 29 ResolveImpl(result);
31 30 } else {
32 31 try {
33 32 m_next.Resolve((TRet)(object)result);
34 33 } catch(Exception error) {
35 34 // handle cast exceptions
36 35 m_next.Reject(error);
37 36 }
38 37 }
39 38 }
40 39
41 40 void ResolveImpl (TIn result) {
42 41 m_fulfilled(result, m_next);
43 42 }
44 43
45 44 public void Reject(Exception error) {
46 if (m_fulfilled != null) {
45 if (m_rejected != null) {
47 46 if (m_dispatcher != null)
48 47 m_dispatcher.Enqueue(RejectImpl, error);
49 48 else
50 49 RejectImpl(error);
51 50 } else {
52 51 m_next.Reject(error);
53 52 }
54 53 }
55 54
56 55 void RejectImpl(Exception error) {
57 56 m_rejected(error, m_next);
58 57 }
59 58
60 59
61 60 public static PromiseFuncReaction<TIn,TRet> Create(Func<TIn,TRet> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) {
62 61 return new PromiseFuncReaction<TIn,TRet>(
63 62 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
64 63 rejected != null ? PromiseHandler.Create(rejected) : null,
65 64 new Deferred<TRet>(),
66 65 dispatcher
67 66 );
68 67 }
69 68
70 69 public static PromiseFuncReaction<TIn,TRet> Create(Func<TIn,IPromise<TRet>> fulfilled, Func<Exception, TRet> rejected, IDispatcher dispatcher) {
71 70 return new PromiseFuncReaction<TIn,TRet>(
72 71 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
73 72 rejected != null ? PromiseHandler.Create(rejected) : null,
74 73 new Deferred<TRet>(),
75 74 dispatcher
76 75 );
77 76 }
78 77
79 78 public static PromiseFuncReaction<TIn,TRet> Create(Func<TIn,TRet> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) {
80 79 return new PromiseFuncReaction<TIn,TRet>(
81 80 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
82 81 rejected != null ? PromiseHandler.Create(rejected) : null,
83 82 new Deferred<TRet>(),
84 83 dispatcher
85 84 );
86 85 }
87 86
88 87 public static PromiseFuncReaction<TIn,TRet> Create(Func<TIn,IPromise<TRet>> fulfilled, Func<Exception, IPromise<TRet>> rejected, IDispatcher dispatcher) {
89 88 return new PromiseFuncReaction<TIn,TRet>(
90 89 fulfilled != null ? PromiseHandler.Create(fulfilled) : null,
91 90 rejected != null ? PromiseHandler.Create(rejected) : null,
92 91 new Deferred<TRet>(),
93 92 dispatcher
94 93 );
95 94 }
96 95 }
97 96 } No newline at end of file
@@ -1,159 +1,158
1 1 using System;
2 using System.Diagnostics;
3 2 using System.Reflection;
4 3 using Implab.Parallels;
5 4
6 5 namespace Implab {
7 6 public class Promise<T> : AbstractEvent<IResolvable<T>>, IPromise<T> {
8 7
9 8 class ResolvableSignal : IResolvable<T> {
10 9 public Signal Signal { get; private set; }
11 10 public ResolvableSignal() {
12 11 Signal = new Signal();
13 12 }
14 13
15 14
16 15 public void Reject(Exception error) {
17 16 Signal.Set();
18 17 }
19 18
20 19 public void Resolve(T result) {
21 20 Signal.Set();
22 21 }
23 22 }
24 23
25 24 class ResolvableWrapper : IResolvable<T> {
26 25 readonly IResolvable m_resolvable;
27 26 public ResolvableWrapper(IResolvable resolvable) {
28 27 m_resolvable = resolvable;
29 28 }
30 29
31 30 public void Reject(Exception reason) {
32 31 m_resolvable.Reject(reason);
33 32 }
34 33
35 34 public void Resolve(T value) {
36 35 m_resolvable.Resolve();
37 36 }
38 37 }
39 38
40 39 PromiseState m_state;
41 40
42 41 T m_result;
43 42
44 43 Exception m_error;
45 44
46 45 public bool IsRejected {
47 46 get {
48 47 return m_state == PromiseState.Rejected;
49 48 }
50 49 }
51 50
52 51 public bool IsFulfilled {
53 52 get {
54 53 return m_state == PromiseState.Fulfilled;
55 54 }
56 55 }
57 56
58 57 public Exception RejectReason {
59 58 get {
60 59 return m_error;
61 60 }
62 61 }
63 62
64 63
65 64 internal void ResolvePromise(T result) {
66 65 if (BeginTransit()) {
67 66 m_result = result;
68 67 m_state = PromiseState.Fulfilled;
69 68 CompleteTransit();
70 69 }
71 70 }
72 71
73 72 internal void RejectPromise(Exception reason) {
74 73 if (BeginTransit()) {
75 74 m_error = reason;
76 75 m_state = PromiseState.Rejected;
77 76 CompleteTransit();
78 77 }
79 78 }
80 79
81 80
82 81 #region implemented abstract members of AbstractPromise
83 82
84 83 protected override void SignalHandler(IResolvable<T> handler) {
85 84 switch (m_state) {
86 85 case PromiseState.Fulfilled:
87 86 handler.Resolve(m_result);
88 87 break;
89 88 case PromiseState.Rejected:
90 89 handler.Reject(RejectReason);
91 90 break;
92 91 default:
93 92 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", m_state));
94 93 }
95 94 }
96 95
97 96 protected void WaitResult(int timeout) {
98 97 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
99 98 throw new TimeoutException();
100 99 }
101 100
102 101 protected Signal GetFulfillSignal() {
103 102 var next = new ResolvableSignal();
104 103 Then(next);
105 104 return next.Signal;
106 105 }
107 106
108 107 #endregion
109 108
110 109 public Type ResultType {
111 110 get {
112 111 return typeof(void);
113 112 }
114 113 }
115 114
116 115
117 116 protected void Rethrow() {
118 117 if (m_error is OperationCanceledException)
119 118 throw new OperationCanceledException("Operation cancelled", m_error);
120 119 else
121 120 throw new TargetInvocationException(m_error);
122 121 }
123 122
124 123 public void Then(IResolvable<T> next) {
125 124 AddHandler(next);
126 125 }
127 126
128 127 public void Then(IResolvable next) {
129 128 AddHandler(new ResolvableWrapper(next));
130 129 }
131 130
132 131 public IPromise<T2> Cast<T2>() {
133 132 return (IPromise<T2>)this;
134 133 }
135 134
136 135 void IPromise.Join() {
137 136 Join();
138 137 }
139 138
140 139 void IPromise.Join(int timeout) {
141 140 Join(timeout);
142 141 }
143 142
144 143 public T Join() {
145 144 WaitResult(-1);
146 145 if (IsRejected)
147 146 Rethrow();
148 147 return m_result;
149 148 }
150 149
151 150 public T Join(int timeout) {
152 151 WaitResult(timeout);
153 152 if (IsRejected)
154 153 Rethrow();
155 154 return m_result;
156 155 }
157 156 }
158 157 }
159 158
@@ -1,193 +1,190
1 1 using System;
2 2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 3 using System.Text.RegularExpressions;
6 4 using System.Diagnostics;
7 5 using System.Collections;
8 6 using System.Runtime.CompilerServices;
9 7 using System.Threading.Tasks;
10 8 using System.Threading;
11 9
12 10 #if NET_4_5
13 11 using System.Threading.Tasks;
14 12 #endif
15 13
16 namespace Implab
17 {
14 namespace Implab {
18 15 public static class Safe
19 16 {
20 17 [MethodImpl(MethodImplOptions.AggressiveInlining)]
21 18 public static void ArgumentAssert(bool condition, string paramName) {
22 19 if (!condition)
23 20 throw new ArgumentException("The parameter is invalid", paramName);
24 21 }
25 22
26 23 [MethodImpl(MethodImplOptions.AggressiveInlining)]
27 24 public static void ArgumentMatch(string value, string paramName, Regex rx) {
28 25 if (rx == null)
29 26 throw new ArgumentNullException("rx");
30 27 if (!rx.IsMatch(value))
31 28 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
32 29 }
33 30
34 31 [MethodImpl(MethodImplOptions.AggressiveInlining)]
35 32 public static void ArgumentNotEmpty(string value, string paramName) {
36 33 if (String.IsNullOrEmpty(value))
37 34 throw new ArgumentException("The parameter can't be empty", paramName);
38 35 }
39 36
40 37 [MethodImpl(MethodImplOptions.AggressiveInlining)]
41 38 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
42 39 if (value == null || value.Length == 0)
43 40 throw new ArgumentException("The array must be not emty", paramName);
44 41 }
45 42
46 43 [MethodImpl(MethodImplOptions.AggressiveInlining)]
47 44 public static void ArgumentNotNull(object value, string paramName) {
48 45 if (value == null)
49 46 throw new ArgumentNullException(paramName);
50 47 }
51 48
52 49 [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 50 internal static void ArgumentGreaterEqThan(int value, int min, string paramName) {
54 51 if (value < min)
55 52 throw new ArgumentOutOfRangeException(paramName);
56 53 }
57 54
58 55 public static object CreateDefaultValue(Type type) {
59 56 if (type.IsValueType)
60 57 return Activator.CreateInstance(type);
61 58
62 59 return null;
63 60 }
64 61
65 62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
66 63 public static void ArgumentInRange(bool condition, string paramName) {
67 64 if (!condition)
68 65 throw new ArgumentOutOfRangeException(paramName);
69 66 }
70 67
71 68 [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 69 public static void ArgumentOfType(object value, Type type, string paramName) {
73 70 if (!type.IsInstanceOfType(value))
74 71 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
75 72 }
76 73
77 74 public static void Dispose(params IDisposable[] objects) {
78 75 if (objects != null)
79 76 foreach (var d in objects)
80 77 if (d != null)
81 78 d.Dispose();
82 79 }
83 80
84 81 public static void Dispose(params object[] objects) {
85 82 if (objects != null)
86 83 foreach (var obj in objects) {
87 84 var d = obj as IDisposable;
88 85 if (d != null)
89 86 d.Dispose();
90 87 }
91 88 }
92 89
93 90 public static void DisposeCollection(IEnumerable<IDisposable> objects) {
94 91 if (objects != null)
95 92 foreach (var d in objects)
96 93 Dispose(d);
97 94 }
98 95
99 96 public static void DisposeCollection(IEnumerable objects) {
100 97 if (objects != null)
101 98 foreach (var d in objects)
102 99 Dispose(d);
103 100 }
104 101
105 102 public static void Dispose(object obj) {
106 103 if (obj is IDisposable)
107 104 Dispose((IDisposable)obj);
108 105
109 106 }
110 107
111 108 [DebuggerStepThrough]
112 109 public static void DispatchEvent<T>(this EventHandler<T> handler, object sender, T args) {
113 110 if (handler != null)
114 111 handler(sender, args);
115 112 }
116 113
117 114 [DebuggerStepThrough]
118 115 public static void DispatchEvent(this EventHandler handler, object sender, EventArgs args) {
119 116 if (handler != null)
120 117 handler(sender, args);
121 118 }
122 119
123 120 [DebuggerStepThrough]
124 121 public static IPromise<T> Run<T>(Func<T> action) {
125 122 ArgumentNotNull(action, "action");
126 123
127 124 try {
128 125 return Promise.Resolve(action());
129 126 } catch (Exception err) {
130 127 return Promise.Reject<T>(err);
131 128 }
132 129 }
133 130
134 131 [DebuggerStepThrough]
135 132 public static IPromise Run(Action action) {
136 133 ArgumentNotNull(action, "action");
137 134
138 135 try {
139 136 action();
140 137 return Promise.Resolve();
141 138 } catch (Exception err) {
142 139 return Promise.Reject(err);
143 140 }
144 141 }
145 142
146 143 [DebuggerStepThrough]
147 144 public static IPromise Run(Func<IPromise> action) {
148 145 ArgumentNotNull(action, "action");
149 146
150 147 try {
151 148 return action() ?? Promise.Reject(new Exception("The action returned null"));
152 149 } catch (Exception err) {
153 150 return Promise.Reject(err);
154 151 }
155 152 }
156 153
157 154 public static void NoWait(IPromise promise) {
158 155 }
159 156
160 157 public static void NoWait(Task promise) {
161 158 }
162 159
163 160 public static void NoWait<T>(Task<T> promise) {
164 161 }
165 162
166 163 public static void Noop() {
167 164 }
168 165
169 166 public static void Noop(CancellationToken ct) {
170 167 ct.ThrowIfCancellationRequested();
171 168 }
172 169
173 170 public static Task CreateTask() {
174 171 return new Task(Noop);
175 172 }
176 173
177 174 public static Task CreateTask(CancellationToken ct) {
178 175 return new Task(Noop, ct);
179 176 }
180 177
181 178 [DebuggerStepThrough]
182 179 public static IPromise<T> Run<T>(Func<IPromise<T>> action) {
183 180 ArgumentNotNull(action, "action");
184 181
185 182 try {
186 183 return action() ?? Promise.Reject<T>(new Exception("The action returned null"));
187 184 } catch (Exception err) {
188 185 return Promise.Reject<T>(err);
189 186 }
190 187 }
191 188
192 189 }
193 190 }
@@ -1,11 +1,7
1 using System;
2
3 namespace Implab.Xml
4 {
5 public enum JsonXmlCaseTransform
6 {
7 None,
8 UcFirst,
9 LcFirst
10 }
1 namespace Implab.Xml {
2 public enum JsonXmlCaseTransform {
3 None,
4 UcFirst,
5 LcFirst
6 }
11 7 } No newline at end of file
@@ -1,664 +1,663
1 1 using Implab.Formats.Json;
2 2 using System;
3 3 using System.Collections.Generic;
4 using System.Globalization;
5 4 using System.IO;
6 5 using System.Linq;
7 6 using System.Xml;
8 7
9 8 namespace Implab.Xml {
10 9 public class JsonXmlReader : XmlReader {
11 10 struct JsonContext {
12 11 public string localName;
13 12 public bool skip;
14 13 }
15 14
16 15 JsonReader m_parser;
17 16 JsonXmlReaderOptions m_options;
18 17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
19 18 XmlNameTable m_nameTable;
20 19
21 20 readonly string m_jsonRootName;
22 21 readonly string m_jsonNamespace;
23 22 readonly string m_jsonPrefix;
24 23 readonly bool m_jsonFlattenArrays;
25 24 readonly string m_jsonArrayItemName;
26 25
27 26 string m_jsonLocalName;
28 27 string m_jsonValueName;
29 28 bool m_jsonSkip; // indicates wheather to generate closing tag for objects or arrays
30 29
31 30 readonly Stack<JsonContext> m_jsonNameStack = new Stack<JsonContext>();
32 31
33 32 XmlQualifiedName m_elementQName;
34 33 string m_elementPrefix;
35 34 int m_elementDepth;
36 35 bool m_elementIsEmpty;
37 36
38 37 XmlQualifiedName m_qName;
39 38 string m_prefix;
40 39 int m_xmlDepth;
41 40
42 41 XmlSimpleAttribute[] m_attributes;
43 42 string m_value;
44 43 bool m_isEmpty;
45 44
46 45 XmlNodeType m_nodeType = XmlNodeType.None;
47 46
48 47 bool m_isAttribute; // indicates that we are reading attribute nodes
49 48 int m_currentAttribute;
50 49 bool m_currentAttributeRead;
51 50
52 51
53 52 XmlNameContext m_context;
54 53
55 54 readonly string m_xmlnsPrefix;
56 55 readonly string m_xmlnsNamespace;
57 56 readonly string m_xsiPrefix;
58 57 readonly string m_xsiNamespace;
59 58 readonly JsonXmlCaseTransform m_caseTransform;
60 59
61 60
62 61 public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) {
63 62 Safe.ArgumentNotNull(parser, nameof(parser));
64 63 m_parser = parser;
65 64
66 65 m_options = options ?? new JsonXmlReaderOptions();
67 66
68 67 m_jsonFlattenArrays = m_options.FlattenArrays;
69 68 m_nameTable = m_options.NameTable ?? new NameTable();
70 69
71 70 m_jsonRootName = m_nameTable.Add(string.IsNullOrEmpty(m_options.RootName) ? "data" : m_options.RootName);
72 71 m_jsonArrayItemName = m_nameTable.Add(string.IsNullOrEmpty(m_options.ArrayItemName) ? "item" : m_options.ArrayItemName);
73 72 m_jsonNamespace = m_nameTable.Add(m_options.NamespaceUri ?? string.Empty);
74 73 m_jsonPrefix = m_nameTable.Add(m_options.NodesPrefix ?? string.Empty);
75 74 m_xmlnsPrefix = m_nameTable.Add(XmlNameContext.XmlnsPrefix);
76 75 m_xmlnsNamespace = m_nameTable.Add(XmlNameContext.XmlnsNamespace);
77 76 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix);
78 77 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace);
79 78
80 79 m_caseTransform = m_options.CaseTransform;
81 80
82 81 // TODO validate m_jsonRootName, m_jsonArrayItemName
83 82
84 83 m_context = new XmlNameContext(null, 0);
85 84 }
86 85
87 86 public override int AttributeCount {
88 87 get {
89 88 return m_attributes == null ? 0 : m_attributes.Length;
90 89 }
91 90 }
92 91
93 92 public override string BaseURI {
94 93 get {
95 94 return string.Empty;
96 95 }
97 96 }
98 97
99 98 public override int Depth {
100 99 get {
101 100 return m_xmlDepth;
102 101 }
103 102 }
104 103
105 104 public override bool EOF {
106 105 get {
107 106 return m_position == JsonXmlReaderPosition.Eof;
108 107 }
109 108 }
110 109
111 110 public override bool IsEmptyElement {
112 111 get { return m_isEmpty; }
113 112 }
114 113
115 114
116 115 public override string LocalName {
117 116 get {
118 117 return m_qName.Name;
119 118 }
120 119 }
121 120
122 121 public override string NamespaceURI {
123 122 get {
124 123 return m_qName.Namespace;
125 124 }
126 125 }
127 126
128 127 public override XmlNameTable NameTable {
129 128 get {
130 129 return m_nameTable;
131 130 }
132 131 }
133 132
134 133 public override XmlNodeType NodeType {
135 134 get {
136 135 return m_nodeType;
137 136 }
138 137 }
139 138
140 139 public override string Prefix {
141 140 get {
142 141 return m_prefix;
143 142 }
144 143 }
145 144
146 145 public override ReadState ReadState {
147 146 get {
148 147 switch (m_position) {
149 148 case JsonXmlReaderPosition.Initial:
150 149 return ReadState.Initial;
151 150 case JsonXmlReaderPosition.Eof:
152 151 return ReadState.EndOfFile;
153 152 case JsonXmlReaderPosition.Closed:
154 153 return ReadState.Closed;
155 154 case JsonXmlReaderPosition.Error:
156 155 return ReadState.Error;
157 156 default:
158 157 return ReadState.Interactive;
159 158 };
160 159 }
161 160 }
162 161
163 162 public override string Value {
164 163 get {
165 164 return m_value;
166 165 }
167 166 }
168 167
169 168 public override string GetAttribute(int i) {
170 169 Safe.ArgumentInRange(i >= 0 && i < AttributeCount, nameof(i));
171 170 return m_attributes[i].Value;
172 171 }
173 172
174 173 public override string GetAttribute(string name) {
175 174 if (m_attributes == null)
176 175 return null;
177 176 var qName = m_context.Resolve(name);
178 177 var attr = Array.Find(m_attributes, x => x.QName == qName);
179 178 var value = attr?.Value;
180 179 return value == string.Empty ? null : value;
181 180 }
182 181
183 182 public override string GetAttribute(string name, string namespaceURI) {
184 183 if (m_attributes == null)
185 184 return null;
186 185 var qName = new XmlQualifiedName(name, namespaceURI);
187 186 var attr = Array.Find(m_attributes, x => x.QName == qName);
188 187 var value = attr?.Value;
189 188 return value == string.Empty ? null : value;
190 189 }
191 190
192 191 public override string LookupNamespace(string prefix) {
193 192 return m_context.ResolvePrefix(prefix);
194 193 }
195 194
196 195 public override bool MoveToAttribute(string name) {
197 196 if (m_attributes == null || m_attributes.Length == 0)
198 197 return false;
199 198
200 199 var qName = m_context.Resolve(name);
201 200 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
202 201 if (index >= 0) {
203 202 MoveToAttributeImpl(index);
204 203 return true;
205 204 }
206 205 return false;
207 206 }
208 207
209 208 public override bool MoveToAttribute(string name, string ns) {
210 209 if (m_attributes == null || m_attributes.Length == 0)
211 210 return false;
212 211
213 212 var qName = m_context.Resolve(name);
214 213 var index = Array.FindIndex(m_attributes, x => x.QName == qName);
215 214 if (index >= 0) {
216 215 MoveToAttributeImpl(index);
217 216 return true;
218 217 }
219 218 return false;
220 219 }
221 220
222 221 void MoveToAttributeImpl(int i) {
223 222 if (!m_isAttribute) {
224 223 m_elementQName = m_qName;
225 224 m_elementDepth = m_xmlDepth;
226 225 m_elementPrefix = m_prefix;
227 226 m_elementIsEmpty = m_isEmpty;
228 227 m_isAttribute = true;
229 228 }
230 229
231 230 var attr = m_attributes[i];
232 231
233 232
234 233 m_currentAttribute = i;
235 234 m_currentAttributeRead = false;
236 235 m_nodeType = XmlNodeType.Attribute;
237 236
238 237 m_xmlDepth = m_elementDepth + 1;
239 238 m_qName = attr.QName;
240 239 m_value = attr.Value;
241 240 m_prefix = attr.Prefix;
242 241 }
243 242
244 243 public override bool MoveToElement() {
245 244 if (m_isAttribute) {
246 245 m_value = null;
247 246 m_nodeType = XmlNodeType.Element;
248 247 m_xmlDepth = m_elementDepth;
249 248 m_prefix = m_elementPrefix;
250 249 m_qName = m_elementQName;
251 250 m_isEmpty = m_elementIsEmpty;
252 251 m_isAttribute = false;
253 252 return true;
254 253 }
255 254 return false;
256 255 }
257 256
258 257 public override bool MoveToFirstAttribute() {
259 258 if (m_attributes != null && m_attributes.Length > 0) {
260 259 MoveToAttributeImpl(0);
261 260 return true;
262 261 }
263 262 return false;
264 263 }
265 264
266 265 public override bool MoveToNextAttribute() {
267 266 if (m_isAttribute) {
268 267 var next = m_currentAttribute + 1;
269 268 if (next < AttributeCount) {
270 269 MoveToAttributeImpl(next);
271 270 return true;
272 271 }
273 272 return false;
274 273 } else {
275 274 return MoveToFirstAttribute();
276 275 }
277 276
278 277 }
279 278
280 279 public override bool ReadAttributeValue() {
281 280 if (!m_isAttribute || m_currentAttributeRead)
282 281 return false;
283 282
284 283 ValueNode(m_attributes[m_currentAttribute].Value);
285 284 m_currentAttributeRead = true;
286 285 return true;
287 286 }
288 287
289 288 public override void ResolveEntity() {
290 289 /* do nothing */
291 290 }
292 291
293 292 /// <summary>
294 293 /// Determines do we need to increase depth after the current node
295 294 /// </summary>
296 295 /// <returns></returns>
297 296 public bool IsSibling() {
298 297 switch (m_nodeType) {
299 298 case XmlNodeType.None: // start document
300 299 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method
301 300 return false;
302 301 case XmlNodeType.Element:
303 302 // if the elemnt is empty the next element will be it's sibling
304 303 return m_isEmpty;
305 304 default:
306 305 return true;
307 306 }
308 307 }
309 308
310 309 void ValueNode(string value) {
311 310 if (!IsSibling()) // the node is nested
312 311 m_xmlDepth++;
313 312
314 313 m_qName = XmlQualifiedName.Empty;
315 314 m_nodeType = XmlNodeType.Text;
316 315 m_prefix = string.Empty;
317 316 m_value = value;
318 317 m_isEmpty = false;
319 318 m_attributes = null;
320 319 }
321 320
322 321 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) {
323 322 if (!IsSibling()) // the node is nested
324 323 m_xmlDepth++;
325 324
326 325 var context = m_context;
327 326 List<XmlSimpleAttribute> definedAttrs = null;
328 327
329 328 // define new namespaces
330 329 if (attrs != null) {
331 330 foreach (var attr in attrs) {
332 331 if (attr.QName.Name == "xmlns") {
333 332 if (context == m_context)
334 333 context = new XmlNameContext(m_context, m_xmlDepth);
335 334 context.DefinePrefix(attr.Value, string.Empty);
336 335 } else if (attr.Prefix == m_xmlnsPrefix) {
337 336 if (context == m_context)
338 337 context = new XmlNameContext(m_context, m_xmlDepth);
339 338 context.DefinePrefix(attr.Value, attr.QName.Name);
340 339 } else {
341 340 string attrPrefix;
342 341 if (string.IsNullOrEmpty(attr.QName.Namespace))
343 342 continue;
344 343
345 344 // auto-define prefixes
346 345 if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
347 346 // new namespace prefix added
348 347 attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace);
349 348 attr.Prefix = attrPrefix;
350 349
351 350 if (definedAttrs == null)
352 351 definedAttrs = new List<XmlSimpleAttribute>();
353 352
354 353 definedAttrs.Add(new XmlSimpleAttribute(attrPrefix, m_xmlnsNamespace, m_xmlnsPrefix, attr.QName.Namespace));
355 354 }
356 355 }
357 356 }
358 357 }
359 358
360 359 string p;
361 360 // auto-define prefixes
362 361 if (!context.LookupNamespacePrefix(ns, out p)) {
363 362 if (context == m_context)
364 363 context = new XmlNameContext(m_context, m_xmlDepth);
365 364 p = context.CreateNamespacePrefix(ns);
366 365 if (definedAttrs == null)
367 366 definedAttrs = new List<XmlSimpleAttribute>();
368 367
369 368 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns));
370 369 }
371 370
372 371 if (definedAttrs != null) {
373 372 if (attrs != null)
374 373 definedAttrs.AddRange(attrs);
375 374 attrs = definedAttrs.ToArray();
376 375 }
377 376
378 377 if (!empty)
379 378 m_context = context;
380 379
381 380 m_nodeType = XmlNodeType.Element;
382 381 m_qName = new XmlQualifiedName(name, ns);
383 382 m_prefix = p;
384 383 m_value = null;
385 384 m_isEmpty = empty;
386 385 m_attributes = attrs;
387 386 }
388 387
389 388 void EndElementNode(string name, string ns) {
390 389 if (IsSibling()) {
391 390 // closing the element which has children
392 391 m_xmlDepth--;
393 392 }
394 393
395 394 string p;
396 395 if (!m_context.LookupNamespacePrefix(ns, out p))
397 396 throw new Exception($"Failed to lookup namespace '{ns}'");
398 397
399 398 if (m_context.Depth == m_xmlDepth)
400 399 m_context = m_context.ParentContext;
401 400
402 401 m_nodeType = XmlNodeType.EndElement;
403 402 m_prefix = p;
404 403 m_qName = new XmlQualifiedName(name, ns);
405 404 m_value = null;
406 405 m_attributes = null;
407 406 m_isEmpty = false;
408 407 }
409 408
410 409 void XmlDeclaration() {
411 410 if (!IsSibling()) // the node is nested
412 411 m_xmlDepth++;
413 412 m_nodeType = XmlNodeType.XmlDeclaration;
414 413 m_qName = new XmlQualifiedName("xml");
415 414 m_value = "version='1.0'";
416 415 m_prefix = string.Empty;
417 416 m_attributes = null;
418 417 m_isEmpty = false;
419 418 }
420 419
421 420 public override bool Read() {
422 421 try {
423 422 string elementName;
424 423 XmlSimpleAttribute[] elementAttrs = null;
425 424 MoveToElement();
426 425
427 426 switch (m_position) {
428 427 case JsonXmlReaderPosition.Initial:
429 428 m_jsonLocalName = m_jsonRootName;
430 429 m_jsonSkip = false;
431 430 XmlDeclaration();
432 431 m_position = JsonXmlReaderPosition.Declaration;
433 432 return true;
434 433 case JsonXmlReaderPosition.Declaration:
435 434 elementAttrs = new[] {
436 435 new XmlSimpleAttribute(m_xsiPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_xsiNamespace),
437 436 string.IsNullOrEmpty(m_jsonPrefix) ?
438 437 new XmlSimpleAttribute(m_xmlnsPrefix, string.Empty, string.Empty, m_jsonNamespace) :
439 438 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace)
440 439 };
441 440 break;
442 441 case JsonXmlReaderPosition.ValueElement:
443 442 if (!m_isEmpty) {
444 443 if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty))
445 444 ValueNode(m_parser.ElementValue);
446 445 else
447 446 goto case JsonXmlReaderPosition.ValueContent;
448 447 m_position = JsonXmlReaderPosition.ValueContent;
449 448 return true;
450 449 } else {
451 450 m_position = JsonXmlReaderPosition.ValueEndElement;
452 451 break;
453 452 }
454 453 case JsonXmlReaderPosition.ValueContent:
455 454 EndElementNode(m_jsonValueName, m_jsonNamespace);
456 455 m_position = JsonXmlReaderPosition.ValueEndElement;
457 456 return true;
458 457 case JsonXmlReaderPosition.Eof:
459 458 case JsonXmlReaderPosition.Closed:
460 459 case JsonXmlReaderPosition.Error:
461 460 return false;
462 461 }
463 462
464 463 while (m_parser.Read()) {
465 464 var jsonName = m_nameTable.Add(TransformJsonName(m_parser.ElementName));
466 465
467 466 switch (m_parser.ElementType) {
468 467 case JsonElementType.BeginObject:
469 468 if (!EnterJsonObject(jsonName, out elementName))
470 469 continue;
471 470
472 471 m_position = JsonXmlReaderPosition.BeginObject;
473 472 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
474 473 break;
475 474 case JsonElementType.EndObject:
476 475 if (!LeaveJsonScope(out elementName))
477 476 continue;
478 477
479 478 m_position = JsonXmlReaderPosition.EndObject;
480 479 EndElementNode(elementName, m_jsonNamespace);
481 480 break;
482 481 case JsonElementType.BeginArray:
483 482 if (!EnterJsonArray(jsonName, out elementName))
484 483 continue;
485 484
486 485 m_position = JsonXmlReaderPosition.BeginArray;
487 486 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
488 487 break;
489 488 case JsonElementType.EndArray:
490 489 if (!LeaveJsonScope(out elementName))
491 490 continue;
492 491
493 492 m_position = JsonXmlReaderPosition.EndArray;
494 493 EndElementNode(elementName, m_jsonNamespace);
495 494 break;
496 495 case JsonElementType.Value:
497 496 if (!VisitJsonValue(jsonName, out m_jsonValueName))
498 497 continue;
499 498
500 499 m_position = JsonXmlReaderPosition.ValueElement;
501 500 if (m_parser.ElementValue == null)
502 501 // generate empty element with xsi:nil="true" attribute
503 502 ElementNode(
504 503 m_jsonValueName,
505 504 m_jsonNamespace,
506 505 new[] {
507 506 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, "true")
508 507 },
509 508 true
510 509 );
511 510 else
512 511 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty));
513 512 break;
514 513 default:
515 514 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");
516 515 }
517 516 return true;
518 517 }
519 518
520 519 m_position = JsonXmlReaderPosition.Eof;
521 520 return false;
522 521 } catch {
523 522 m_position = JsonXmlReaderPosition.Error;
524 523 throw;
525 524 }
526 525 }
527 526
528 527 void SaveJsonName() {
529 528 m_jsonNameStack.Push(new JsonContext {
530 529 skip = m_jsonSkip,
531 530 localName = m_jsonLocalName
532 531 });
533 532
534 533 }
535 534
536 535 bool EnterJsonObject(string name, out string elementName) {
537 536 SaveJsonName();
538 537 m_jsonSkip = false;
539 538
540 539 if (string.IsNullOrEmpty(name)) {
541 540 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
542 541 m_jsonLocalName = m_jsonArrayItemName;
543 542 } else {
544 543 m_jsonLocalName = name;
545 544 }
546 545
547 546 elementName = m_jsonLocalName;
548 547 return true;
549 548 }
550 549
551 550 /// <summary>
552 551 /// Called when JSON parser visits BeginArray ('[') element.
553 552 /// </summary>
554 553 /// <param name="name">Optional property name if the array is the member of an object</param>
555 554 /// <returns>true if element should be emited, false otherwise</returns>
556 555 bool EnterJsonArray(string name, out string elementName) {
557 556 SaveJsonName();
558 557
559 558 if (string.IsNullOrEmpty(name)) {
560 559 // m_jsonNameStack.Count == 1 means the root node
561 560 if (m_jsonNameStack.Count != 1 && !m_jsonFlattenArrays)
562 561 m_jsonLocalName = m_jsonArrayItemName;
563 562
564 563 m_jsonSkip = false; // we should not flatten arrays inside arrays or in the document root
565 564 } else {
566 565 m_jsonLocalName = name;
567 566 m_jsonSkip = m_jsonFlattenArrays;
568 567 }
569 568 elementName = m_jsonLocalName;
570 569
571 570 return !m_jsonSkip;
572 571 }
573 572
574 573 bool VisitJsonValue(string name, out string elementName) {
575 574 if (string.IsNullOrEmpty(name)) {
576 575 // m_jsonNameStack.Count == 0 means that JSON document consists from simple value
577 576 elementName = (m_jsonNameStack.Count == 0 || m_jsonFlattenArrays) ? m_jsonLocalName : m_jsonArrayItemName;
578 577 } else {
579 578 elementName = name;
580 579 }
581 580 return true;
582 581 }
583 582
584 583 bool LeaveJsonScope(out string elementName) {
585 584 elementName = m_jsonLocalName;
586 585 var skip = m_jsonSkip;
587 586
588 587 var prev = m_jsonNameStack.Pop();
589 588 m_jsonLocalName = prev.localName;
590 589 m_jsonSkip = prev.skip;
591 590
592 591 return !skip;
593 592 }
594 593
595 594 private string TransformJsonName(string name) {
596 595 if (m_caseTransform == JsonXmlCaseTransform.None || string.IsNullOrEmpty(name)) {
597 596 return name;
598 597 } else if (m_caseTransform == JsonXmlCaseTransform.UcFirst) {
599 598 return JsonXmlReader.UppercaseFirst(name);
600 599 } else {
601 600 return JsonXmlReader.LowercaseFirst(name);
602 601 }
603 602 }
604 603
605 604 protected override void Dispose(bool disposing) {
606 605 if (disposing)
607 606 Safe.Dispose(m_parser);
608 607 base.Dispose(true);
609 608 }
610 609
611 610 public override string ToString() {
612 611 switch (NodeType) {
613 612 case XmlNodeType.Element:
614 613 return $"<{Name} {string.Join(" ", (m_attributes ?? new XmlSimpleAttribute[0]).Select(x => $"{x.Prefix}{(string.IsNullOrEmpty(x.Prefix) ? "" : ":")}{x.QName.Name}='{x.Value}'"))} {(IsEmptyElement ? "/" : "")}>";
615 614 case XmlNodeType.Attribute:
616 615 return $"@{Name}";
617 616 case XmlNodeType.Text:
618 617 return $"{Value}";
619 618 case XmlNodeType.CDATA:
620 619 return $"<![CDATA[{Value}]]>";
621 620 case XmlNodeType.EntityReference:
622 621 return $"&{Name};";
623 622 case XmlNodeType.EndElement:
624 623 return $"</{Name}>";
625 624 default:
626 625 return $".{NodeType} {Name} {Value}";
627 626 }
628 627 }
629 628
630 629 #region static methods
631 630
632 631 //
633 632 // Static Methods
634 633 //
635 634 private static string LowercaseFirst(string s) {
636 635 char[] array = s.ToCharArray();
637 636 array[0] = char.ToLower(array[0]);
638 637 return new string(array);
639 638 }
640 639
641 640 private static string UppercaseFirst(string s) {
642 641 char[] array = s.ToCharArray();
643 642 array[0] = char.ToUpper(array[0]);
644 643 return new string(array);
645 644 }
646 645
647 646 public static JsonXmlReader CreateJsonXmlReader(TextReader textReader, JsonXmlReaderOptions options = null) {
648 647 var jsonReader = JsonReader.Create(textReader);
649 648 return new JsonXmlReader(jsonReader, options);
650 649 }
651 650
652 651 public static JsonXmlReader CreateJsonXmlReader(Stream stream, JsonXmlReaderOptions options = null) {
653 652 var jsonReader = JsonReader.Create(stream);
654 653 return new JsonXmlReader(jsonReader, options);
655 654 }
656 655
657 656 public static JsonXmlReader CreateJsonXmlReader(string file, JsonXmlReaderOptions options = null) {
658 657 var jsonReader = JsonReader.Create(file);
659 658 return new JsonXmlReader(jsonReader, options);
660 659 }
661 660
662 661 #endregion
663 662 }
664 663 }
@@ -1,22 +1,16
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Xml {
1 namespace Implab.Xml {
8 2 enum JsonXmlReaderPosition {
9 3 Initial,
10 4 Declaration,
11 5 BeginArray,
12 6 BeginObject,
13 7 EndArray,
14 8 EndObject,
15 9 ValueElement,
16 10 ValueContent,
17 11 ValueEndElement,
18 12 Eof,
19 13 Closed,
20 14 Error
21 15 }
22 16 }
@@ -1,93 +1,88
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
1 using System.IO;
5 2 using System.Reflection;
6 using System.Text;
7 using System.Threading.Tasks;
8 3 using System.Xml;
9 4 using System.Xml.Linq;
10 5 using System.Xml.Serialization;
11 6
12 7 namespace Implab.Xml {
13 8 public static class SerializationHelpers {
14 9 public static string SerializeAsString<T>(T obj) {
15 10 return XmlDefaultSerializer<T>.Instance.SerializeAsString(obj);
16 11 }
17 12
18 13 public static void Serialize<T>(XmlWriter writer, T obj) {
19 14 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
20 15 }
21 16
22 17 public static XmlDocument SerializeAsXmlDocument<T>(T obj) {
23 18 var doc = new XmlDocument();
24 19 using (var writer = doc.CreateNavigator().AppendChild()) {
25 20 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
26 21 }
27 22 return doc;
28 23 }
29 24
30 25 public static XDocument SerializeAsXDocument<T>(T obj) {
31 26 var doc = new XDocument();
32 27 using (var writer = doc.CreateWriter()) {
33 28 XmlDefaultSerializer<T>.Instance.Serialize(writer, obj);
34 29 }
35 30 return doc;
36 31 }
37 32
38 33 public static void SerializeToFile<T>(string file, T obj) {
39 34 XmlDefaultSerializer<T>.Instance.SerializeToFile(obj, file);
40 35 }
41 36
42 37 public static void SerializeToElementChild<T>(XmlElement element, T obj) {
43 38 XmlDefaultSerializer<T>.Instance.Serialize(obj, element);
44 39 }
45 40
46 41 public static T Deserialize<T>(XmlReader reader) {
47 42 return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
48 43 }
49 44
50 45 public static T DeserializeFromFile<T>(string file) {
51 46 return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromFile(file);
52 47 }
53 48
54 49 public static T DeserializeFromString<T>(string data) {
55 50 return (T)XmlDefaultSerializer<T>.Instance.DeserializeFromString(data);
56 51 }
57 52
58 53 public static T DeserializeFromXmlNode<T>(XmlNode node) {
59 54 Safe.ArgumentNotNull(node, nameof(node));
60 55 using (var reader = node.CreateNavigator().ReadSubtree())
61 56 return (T)XmlDefaultSerializer<T>.Instance.Deserialize(reader);
62 57 }
63 58
64 59 public static T DeserializeJson<T>(TextReader textReader) {
65 60 var options = new JsonXmlReaderOptions {
66 61 NamespaceUri = typeof(T).GetCustomAttribute<XmlRootAttribute>()?.Namespace,
67 62 RootName = typeof(T).Name,
68 63 FlattenArrays = true
69 64 };
70 65
71 66 using (var reader = JsonXmlReader.CreateJsonXmlReader(textReader, options))
72 67 return Deserialize<T>(reader);
73 68 }
74 69
75 70 public static T DeserializeJsonFromString<T>(string data) {
76 71 using (var reader = new StringReader(data)) {
77 72 return DeserializeJson<T>(reader);
78 73 }
79 74 }
80 75
81 76 public static void SerializeJson<T>(TextWriter writer, T obj) {
82 77 var doc = SerializeAsXmlDocument(obj);
83 78 XmlToJson.Default.Transform(doc, null, writer);
84 79 }
85 80
86 81 public static string SerializeJsonAsString<T>(T obj) {
87 82 using (var writer = new StringWriter()) {
88 83 SerializeJson(writer, obj);
89 84 return writer.ToString();
90 85 }
91 86 }
92 87 }
93 88 }
@@ -1,77 +1,73
1 1 using Implab.Components;
2 2 using System;
3 using System.Collections.Generic;
4 3 using System.IO;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 4 using System.Xml;
9 5 using System.Xml.Serialization;
10 6
11 7 namespace Implab.Xml {
12 8 [Obsolete("this class will be removed, use XmlDefaultSerializer")]
13 9 public class SerializersPool<T> : ObjectPool<XmlSerializer> {
14 10
15 11 static readonly SerializersPool<T> _instance = new SerializersPool<T>();
16 12
17 13 public static SerializersPool<T> Instance {
18 14 get { return _instance; }
19 15 }
20 16
21 17 #region implemented abstract members of ObjectPool
22 18 protected override XmlSerializer CreateInstance() {
23 19 return new XmlSerializer(typeof(T));
24 20 }
25 21 #endregion
26 22
27 23 public T DeserializeFromString(string data) {
28 24 using (var reader = new StringReader(data)) {
29 25 return Deserialize(reader);
30 26 }
31 27 }
32 28
33 29 public T Deserialize(TextReader reader) {
34 30 var sr = Allocate();
35 31 try {
36 32 return (T)sr.Deserialize(reader);
37 33 } finally {
38 34 Release(sr);
39 35 }
40 36 }
41 37
42 38 public T Deserialize(XmlReader reader) {
43 39 var sr = Allocate();
44 40 try {
45 41 return (T)sr.Deserialize(reader);
46 42 } finally {
47 43 Release(sr);
48 44 }
49 45 }
50 46
51 47 public string SerializeAsString(T data) {
52 48 using (var writer = new StringWriter()) {
53 49 Serialize(writer, data);
54 50 return writer.ToString();
55 51 }
56 52 }
57 53
58 54 public void Serialize(TextWriter writer, T data) {
59 55 var sr = Allocate();
60 56 try {
61 57 sr.Serialize(writer, data);
62 58 } finally {
63 59 Release(sr);
64 60 }
65 61 }
66 62
67 63 public void Serialize(XmlWriter writer, T data) {
68 64 var sr = Allocate();
69 65 try {
70 66 sr.Serialize(writer, data);
71 67 } finally {
72 68 Release(sr);
73 69 }
74 70 }
75 71
76 72 }
77 73 }
@@ -1,119 +1,116
1 1 using System;
2 2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 3 using System.Xml;
7 4
8 5 namespace Implab.Xml {
9 6 class XmlNameContext {
10 7 public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/";
11 8 public const string XmlnsPrefix = "xmlns";
12 9 public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
13 10 public const string XmlPrefix = "xml";
14 11 public const string XsiNamespace = "http://www.w3.org/2001/XMLSchema-instance";
15 12 public const string XsiPrefix = "xsi";
16 13
17 14 readonly static char[] _qNameDelim = new[] { ':' };
18 15
19 16 Dictionary<string, string> m_ns2prefix;
20 17 Dictionary<string, string> m_prefix2ns;
21 18 int m_nextPrefix = 1;
22 19 string m_lastNs;
23 20 string m_lastPrefix;
24 21
25 22 public XmlNameContext ParentContext { get; private set; }
26 23
27 24 public int Depth { get; private set; }
28 25
29 26 public XmlNameContext(XmlNameContext parent, int depth) {
30 27 ParentContext = parent;
31 28 Depth = depth;
32 29
33 30 if (parent == null) {
34 31 DefinePrefixNoCheck(XmlnsNamespace, XmlnsPrefix);
35 32 DefinePrefixNoCheck(XmlNamespace, XmlPrefix);
36 33 } else {
37 34 m_nextPrefix = parent.m_nextPrefix;
38 35 }
39 36 }
40 37
41 38 public bool LookupNamespacePrefix(string ns, out string prefix) {
42 39 if (ns == null)
43 40 ns = string.Empty;
44 41 if (ns == m_lastNs) {
45 42 prefix = m_lastPrefix;
46 43 return true;
47 44 }
48 45
49 46
50 47 prefix = null;
51 48 for (var ctx = this; ctx != null; ctx = ctx.ParentContext) {
52 49 if (ctx.m_ns2prefix != null && ctx.m_ns2prefix.TryGetValue(ns, out prefix)) {
53 50 m_lastNs = ns;
54 51 m_lastPrefix = prefix;
55 52 return true;
56 53 }
57 54 }
58 55 return false;
59 56 }
60 57
61 58 public string CreateNamespacePrefix(string ns) {
62 59 var prefix = $"p{m_nextPrefix++}";
63 60 DefinePrefixNoCheck(ns, prefix);
64 61 return prefix;
65 62 }
66 63
67 64 void DefinePrefixNoCheck(string ns, string prefix) {
68 65 if (ns == null)
69 66 ns = string.Empty;
70 67 if (prefix == null)
71 68 prefix = string.Empty;
72 69
73 70 if (m_ns2prefix == null)
74 71 m_ns2prefix = new Dictionary<string, string>();
75 72 m_ns2prefix[ns] = prefix;
76 73
77 74 if (m_prefix2ns == null)
78 75 m_prefix2ns = new Dictionary<string, string>();
79 76 m_prefix2ns[prefix] = ns;
80 77 }
81 78
82 79 public void DefinePrefix(string ns, string prefix) {
83 80 // according to https://www.w3.org/TR/xml-names/#ns-decl
84 81
85 82 // It MUST NOT be declared . Other prefixes MUST NOT be bound to this namespace name, and it MUST NOT be declared as the default namespace
86 83 if (ns == XmlnsNamespace)
87 84 throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
88 85
89 86 // It MAY, but need not, be declared, and MUST NOT be bound to any other namespace name
90 87 if (ns == XmlNamespace && prefix != XmlPrefix)
91 88 throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'");
92 89
93 90 // add mapping
94 91 DefinePrefixNoCheck(ns, prefix);
95 92 }
96 93
97 94 public string ResolvePrefix(string prefix) {
98 95 if (prefix == null)
99 96 prefix = string.Empty;
100 97 string ns = null;
101 98 for(var ctx = this; ctx != null; ctx = ctx.ParentContext) {
102 99 if (ctx.m_prefix2ns != null && ctx.m_prefix2ns.TryGetValue(prefix, out ns) == true)
103 100 return ns;
104 101 }
105 102 return null;
106 103 }
107 104
108 105 public XmlQualifiedName Resolve(string name) {
109 106 Safe.ArgumentNotEmpty(name, nameof(name));
110 107 var parts = name.Split(_qNameDelim, 2, StringSplitOptions.RemoveEmptyEntries);
111 108
112 109 if (parts.Length == 2) {
113 110 return new XmlQualifiedName(parts[1], ResolvePrefix(parts[0]));
114 111 } else {
115 112 return new XmlQualifiedName(parts[0], ResolvePrefix(string.Empty));
116 113 }
117 114 }
118 115 }
119 116 }
@@ -1,22 +1,17
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using System.Xml;
1 using System.Xml;
7 2
8 3 namespace Implab.Xml {
9 4 public class XmlSimpleAttribute {
10 5 public XmlSimpleAttribute(string name, string ns, string prefix, string value) {
11 6 QName = new XmlQualifiedName(name, ns);
12 7 Prefix = prefix;
13 8 Value = value;
14 9 }
15 10
16 11 public XmlQualifiedName QName { get; set; }
17 12
18 13 public string Prefix { get; set; }
19 14
20 15 public string Value { get; set; }
21 16 }
22 17 }
@@ -1,33 +1,31
1 using System;
2 1 using System.IO;
3 2 using System.Reflection;
4 3 using System.Xml;
5 4 using System.Xml.Xsl;
6 5 using Implab.Components;
7 using Implab.Formats.Json;
8 6
9 7 namespace Implab.Xml {
10 8 public class XmlToJson {
11 9 const string XmlToJsonTransformId = "Implab.Xml.json.xsl";
12 10
13 11 static LazyAndWeak<XslCompiledTransform> m_default = new LazyAndWeak<XslCompiledTransform>(CreateTransform, true);
14 12
15 13 public static XslCompiledTransform Default {
16 14 get { return m_default.Value; }
17 15 }
18 16
19 17 protected static XslCompiledTransform CreateTransform() {
20 18 var transform = new XslCompiledTransform();
21 19 using(var reader = XmlReader.Create(GetDefaultTransform())) {
22 20 transform.Load(reader);
23 21 }
24 22 return transform;
25 23 }
26 24
27 25 protected static Stream GetDefaultTransform() {
28 26 return Assembly.GetExecutingAssembly().GetManifestResourceStream(XmlToJsonTransformId);
29 27 }
30 28
31 29
32 30 }
33 31 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now