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