Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 64 additions & 47 deletions Orm/Xtensive.Orm/Collections/BindingCollection.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Copyright (C) 2003-2010 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Copyright (C) 2009-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexis Kochetov
// Created: 2009.03.12

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Xtensive.Core;


namespace Xtensive.Collections
Expand All @@ -21,8 +20,50 @@ namespace Xtensive.Collections
/// </summary>
[Serializable]
[DebuggerDisplay("Count = {Count}")]
public class BindingCollection<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
public class BindingCollection<TKey, TValue> : IReadOnlyCollection<KeyValuePair<TKey, TValue>>
{
public readonly ref struct BindingScope
{
public static BindingScope Empty => new BindingScope();

private readonly BindingCollection<TKey, TValue> owner;
private readonly TKey key;
private readonly TValue prevValue;
private readonly bool prevValueExists;

public void Dispose()
{
if (owner == null) {
return;
}

if (prevValueExists) {
if (!owner.permanentBindings.Contains(key)) {
owner.bindings[key] = prevValue;
}
}
else {
if (!owner.permanentBindings.Contains(key)) {
owner.bindings.Remove(key);
}
}
}

public BindingScope(BindingCollection<TKey, TValue> owner, TKey key) : this()
{
this.owner = owner;
this.key = key;
}

public BindingScope(BindingCollection<TKey, TValue> owner, TKey key, TValue prevValue)
{
this.owner = owner;
this.key = key;
this.prevValue = prevValue;
prevValueExists = true;
}
}

[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
private readonly Dictionary<TKey, TValue> bindings = new Dictionary<TKey, TValue>();
private readonly HashSet<TKey> permanentBindings = new HashSet<TKey>();
Expand All @@ -32,7 +73,7 @@ public class BindingCollection<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TV
/// </summary>
public virtual int Count {
[DebuggerStepThrough]
get { return bindings.Count; }
get => bindings.Count;
}

/// <summary>
Expand All @@ -41,7 +82,7 @@ public virtual int Count {
/// <value></value>
public virtual TValue this[TKey key] {
[DebuggerStepThrough]
get { return bindings[key]; }
get => bindings[key];
}

/// <summary>
Expand All @@ -51,24 +92,15 @@ public virtual TValue this[TKey key] {
/// <param name="value">The value to bind.</param>
/// <returns>Disposable object that will
/// destroy the binding on its disposal.</returns>
public virtual IDisposable Add(TKey key, TValue value)
public virtual BindingScope Add(TKey key, TValue value)
{
TValue previous;

if (bindings.TryGetValue(key, out previous)) {
if (bindings.TryGetValue(key, out var previous)) {
bindings[key] = value;
return new Disposable(isDisposing => {
if (!permanentBindings.Contains(key))
bindings[key] = previous;
});
}
else {
bindings.Add(key, value);
return new Disposable(isDisposing => {
if (!permanentBindings.Contains(key))
bindings.Remove(key);
});
return new BindingScope(this, key, previous);
}

bindings.Add(key, value);
return new BindingScope(this, key);
}

/// <summary>
Expand All @@ -80,8 +112,9 @@ public virtual IDisposable Add(TKey key, TValue value)
public virtual void PermanentAdd(TKey key, TValue value)
{
bindings[key] = value;
if (!permanentBindings.Contains(key))
if (!permanentBindings.Contains(key)) {
permanentBindings.Add(key);
}
}

/// <summary>
Expand All @@ -92,8 +125,10 @@ public virtual void PermanentAdd(TKey key, TValue value)
/// <exception cref="KeyNotFoundException">Key isn't found.</exception>
public virtual void ReplaceBound(TKey key, TValue value)
{
if (!bindings.ContainsKey(key))
if (!bindings.ContainsKey(key)) {
throw new KeyNotFoundException();
}

bindings[key] = value;
}

Expand All @@ -108,45 +143,27 @@ public virtual void ReplaceBound(TKey key, TValue value)
/// contains an element with the specified key;
/// otherwise, <see langword="false" />.</returns>
[DebuggerStepThrough]
public virtual bool TryGetValue(TKey key, out TValue value)
{
return bindings.TryGetValue(key, out value);
}
public virtual bool TryGetValue(TKey key, out TValue value) => bindings.TryGetValue(key, out value);

/// <summary>
/// Gets the sequence of bound keys.
/// </summary>
/// <returns>The sequence of bound keys.</returns>
public virtual IEnumerable GetKeys()
{
foreach (var key in bindings.Keys)
foreach (var key in bindings.Keys) {
yield return key;
}
}

#region IEnumerable<...> methods

/// <inheritdoc/>
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return bindings.GetEnumerator();
}
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => bindings.GetEnumerator();

/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

#endregion


// Constructors

/// <summary>
/// Initializes new instance of this type.
/// </summary>
public BindingCollection()
{
}
}
}
60 changes: 41 additions & 19 deletions Orm/Xtensive.Orm/Orm/Linq/LinqBindingCollection.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,67 @@
// Copyright (C) 2003-2010 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Copyright (C) 2009-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexey Gamzov
// Created: 2009.06.30

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Xtensive.Collections;
using Xtensive.Core;
using Xtensive.Orm.Linq.Expressions;

namespace Xtensive.Orm.Linq
{
[Serializable]
internal class LinqBindingCollection : BindingCollection<ParameterExpression, ProjectionExpression>
{
internal readonly ref struct ParameterScope
{
private readonly LinqBindingCollection owner;
private readonly IReadOnlyCollection<ParameterExpression> parameters;

public void Dispose()
{
var linkedParameters = owner.linkedParameters;
foreach (var parameter in parameters) {
linkedParameters.Remove(parameter);
}
}

public ParameterScope(LinqBindingCollection owner, IReadOnlyCollection<ParameterExpression> parameters)
{
this.owner = owner;
this.parameters = parameters;
}
}

private readonly Dictionary<ParameterExpression, IEnumerable<ParameterExpression>> linkedParameters
= new Dictionary<ParameterExpression, IEnumerable<ParameterExpression>>();

public override IDisposable Add(ParameterExpression key, ProjectionExpression value)
public override BindingScope Add(ParameterExpression key, ProjectionExpression value)
{
if (!key.Type.IsAssignableFrom(value.ItemProjector.Type))
throw new ArgumentException(Strings.ExParameterExpressionMustHaveSameTypeAsProjectionExpressionItemProjector, "key");
if (!key.Type.IsAssignableFrom(value.ItemProjector.Type)) {
throw new ArgumentException(
Strings.ExParameterExpressionMustHaveSameTypeAsProjectionExpressionItemProjector, nameof(key));
}

return base.Add(key, value);
}

public override void PermanentAdd(ParameterExpression key, ProjectionExpression value)
{
if (!key.Type.IsAssignableFrom(value.ItemProjector.Type))
throw new ArgumentException(Strings.ExParameterExpressionMustHaveSameTypeAsProjectionExpressionItemProjector, "key");
if (!key.Type.IsAssignableFrom(value.ItemProjector.Type)) {
throw new ArgumentException(
Strings.ExParameterExpressionMustHaveSameTypeAsProjectionExpressionItemProjector, nameof(key));
}

base.PermanentAdd(key, value);
}

public override void ReplaceBound(ParameterExpression key, ProjectionExpression value)
{
base.ReplaceBound(key, value);
IEnumerable<ParameterExpression> parameters;
if (linkedParameters.TryGetValue(key, out parameters)) {
if (linkedParameters.TryGetValue(key, out var parameters)) {
foreach (var parameter in parameters) {
if (parameter!=key) {
var projection = this[parameter];
Expand All @@ -52,16 +76,14 @@ public override void ReplaceBound(ParameterExpression key, ProjectionExpression
}
}
}
public Disposable LinkParameters(IEnumerable<ParameterExpression> parameters)

public ParameterScope LinkParameters(IReadOnlyCollection<ParameterExpression> parameters)
{
foreach (var parameter in parameters)
foreach (var parameter in parameters) {
linkedParameters.Add(parameter, parameters);
return new Disposable(isDisposing => {
foreach (var parameter in parameters) {
linkedParameters.Remove(parameter);
}
});
}

return new ParameterScope(this, parameters);
}
}
}
10 changes: 5 additions & 5 deletions Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2010 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Copyright (C) 2009-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexis Kochetov
// Created: 2009.02.27

Expand Down Expand Up @@ -1072,7 +1072,7 @@ private ProjectionExpression VisitSelectMany(Expression source, LambdaExpression
var visitedSource = Visit(source);
var sequence = VisitSequence(visitedSource);

IDisposable indexBinding = null;
var indexBinding = BindingCollection<ParameterExpression, ProjectionExpression>.BindingScope.Empty;
if (collectionSelector.Parameters.Count==2) {
var indexProjection = GetIndexBinding(collectionSelector, ref sequence);
indexBinding = context.Bindings.Add(collectionSelector.Parameters[1], indexProjection);
Expand Down Expand Up @@ -1191,7 +1191,7 @@ private ProjectionExpression VisitWhere(Expression expression, LambdaExpression
{
var parameter = le.Parameters[0];
ProjectionExpression visitedSource = VisitSequence(expression);
IDisposable indexBinding = null;
var indexBinding = BindingCollection<ParameterExpression, ProjectionExpression>.BindingScope.Empty;
if (le.Parameters.Count==2) {
var indexProjection = GetIndexBinding(le, ref visitedSource);
indexBinding = context.Bindings.Add(le.Parameters[1], indexProjection);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
// Copyright (C) 2010 Xtensive LLC.
// All rights reserved.
// For conditions of distribution and use, see license.
// Copyright (C) 2010-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
// Created by: Alexey Gamzov
// Created: 2010.01.21

using System;
using Xtensive.Core;


namespace Xtensive.Orm.Rse.Transformation
{
internal sealed class SkipTakeRewriterState
{
internal readonly ref struct SkipTakeRewriterScope
{
private readonly SkipTakeRewriter rewriter;
private readonly SkipTakeRewriterState prevState;

public void Dispose() => rewriter.State = prevState;

public SkipTakeRewriterScope(SkipTakeRewriter rewriter, SkipTakeRewriterState prevState)
{
this.rewriter = rewriter;
this.prevState = prevState;
}
}

private readonly SkipTakeRewriter rewriter;

public Func<int> Skip { get; private set; }
Expand Down Expand Up @@ -56,12 +68,11 @@ private static Func<int> PositiveSelector(Func<int> valueSelector)
};
}

public IDisposable CreateScope()
public SkipTakeRewriterScope CreateScope()
{
var currentState = rewriter.State;
var newState = new SkipTakeRewriterState(currentState);
rewriter.State = newState;
return new Disposable(_ => rewriter.State = currentState);
rewriter.State = new SkipTakeRewriterState(currentState);
return new SkipTakeRewriterScope(rewriter, currentState);
}


Expand Down