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
20 changes: 20 additions & 0 deletions ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,25 @@ Architecture architecture
(arg.Item1, arg.Item2 is Type type ? architecture.GetITypeOfType(type) : arg.Item2)
);
}

/// <summary>
/// Creates a lookup function for the given collection of elements.
/// For smaller collections, it uses the Contains method of the collection directly.
/// For larger collections, it creates a HashSet for O(1) average time complexity lookups.
/// </summary>
///
/// <typeparam name="T">The type of elements in the collection.</typeparam>
///
/// <param name="elements">The collection of elements to create a lookup function for.</param>
///
/// <returns>A function that checks if an element is in the collection.</returns>
public static Func<T, bool> CreateLookupFn<T>(ICollection<T> elements)
{
if (elements.Count < 20)
{
return elements.Contains;
}
return new HashSet<T>(elements).Contains;
}
}
}
2 changes: 1 addition & 1 deletion ArchUnitNET/Domain/UnavailableType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public override string ToString()
return FullName;
}

private bool Equals(Struct other)
private bool Equals(UnavailableType other)
{
return Equals(Type, other.Type);
}
Expand Down
59 changes: 40 additions & 19 deletions ArchUnitNET/Fluent/ConditionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,34 @@ ICanBeEvaluated archRuleCreator
var filteredObjectsList = filteredObjects.ToList();
if (filteredObjectsList.IsNullOrEmpty() && !CheckEmpty())
{
yield return new EvaluationResult(
null,
new StringIdentifier(""),
false,
"There are no objects matching the criteria",
archRuleCreator,
architecture
return new[]
{
new EvaluationResult(
null,
new StringIdentifier(""),
false,
"There are no objects matching the criteria",
archRuleCreator,
architecture
),
};
}

if (_conditionElements.All(e => e.IsOrdered()))
{
var conditionResults = _conditionElements
.Select(conditionElement =>
conditionElement.Check(filteredObjectsList, architecture).ToList()
)
.ToList();
return filteredObjectsList.Select(
(t, i) =>
CreateEvaluationResult(
conditionResults.Select(results => results[i]),
architecture,
archRuleCreator
)
);
yield break;
}

//rough heuristic - if we have small number of comparisons, we are fine with sequential search
Expand All @@ -129,14 +148,13 @@ ICanBeEvaluated archRuleCreator
)
.ToList();

foreach (var t in filteredObjectsList)
{
yield return CreateEvaluationResult(
return filteredObjectsList.Select(t =>
CreateEvaluationResult(
FindResultsForObject(conditionResults, t),
architecture,
archRuleCreator
);
}
)
);
}
else
{
Expand All @@ -145,15 +163,13 @@ ICanBeEvaluated archRuleCreator
conditionElement.Check(filteredObjectsList, architecture).ToList()
)
.ToList();

foreach (var t in filteredObjectsList)
{
yield return CreateEvaluationResult(
return filteredObjectsList.Select(t =>
CreateEvaluationResult(
FindResultsForObject(conditionResults, t),
architecture,
archRuleCreator
);
}
)
);
}
}

Expand Down Expand Up @@ -349,6 +365,11 @@ Architecture architecture
.Select(result => new ConditionElementResult(result, _logicalConjunction));
}

public bool IsOrdered()
{
return _condition is IOrderedCondition<T>;
}

public bool CheckEmpty(bool currentResult)
{
if (_condition == null)
Expand Down
40 changes: 0 additions & 40 deletions ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,6 @@ private readonly Func<
IEnumerable<ConditionResult>
> _condition;

public ArchitectureCondition(
Func<TRuleType, Architecture, bool> condition,
string description,
string failDescription
)
{
_condition = (ruleTypes, architecture) =>
ruleTypes.Select(type => new ConditionResult(
type,
condition(type, architecture),
failDescription
));
Description = description;
}

public ArchitectureCondition(
Func<TRuleType, Architecture, ConditionResult> condition,
string description
)
{
_condition = (ruleTypes, architecture) =>
ruleTypes.Select(type => condition(type, architecture));
Description = description;
}

public ArchitectureCondition(
Func<IEnumerable<TRuleType>, Architecture, IEnumerable<ConditionResult>> condition,
string description
Expand All @@ -48,21 +23,6 @@ string description
Description = description;
}

public ArchitectureCondition(
Func<TRuleType, Architecture, bool> condition,
Func<TRuleType, Architecture, string> dynamicFailDescription,
string description
)
{
_condition = (ruleTypes, architecture) =>
ruleTypes.Select(type => new ConditionResult(
type,
condition(type, architecture),
dynamicFailDescription(type, architecture)
));
Description = description;
}

public string Description { get; }

public IEnumerable<ConditionResult> Check(
Expand Down
2 changes: 1 addition & 1 deletion ArchUnitNET/Fluent/Conditions/ExistsCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace ArchUnitNET.Fluent.Conditions
{
public class ExistsCondition<TRuleType> : ICondition<TRuleType>
public class ExistsCondition<TRuleType> : IOrderedCondition<TRuleType>
where TRuleType : ICanBeAnalyzed
{
private readonly bool _valueIfExists;
Expand Down
7 changes: 7 additions & 0 deletions ArchUnitNET/Fluent/Conditions/IOrderedCondition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using ArchUnitNET.Domain;

namespace ArchUnitNET.Fluent.Conditions
{
public interface IOrderedCondition<in TRuleType> : ICondition<TRuleType>
where TRuleType : ICanBeAnalyzed { }
}
59 changes: 59 additions & 0 deletions ArchUnitNET/Fluent/Conditions/OrderedArchitectureCondition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ArchUnitNET.Domain;

namespace ArchUnitNET.Fluent.Conditions
{
public class OrderedArchitectureCondition<TRuleType>
: ArchitectureCondition<TRuleType>,
IOrderedCondition<TRuleType>
where TRuleType : ICanBeAnalyzed
{
public OrderedArchitectureCondition(
Func<TRuleType, Architecture, bool> condition,
string description,
string failDescription
)
: base(
(ruleTypes, architecture) =>
ruleTypes.Select(type => new ConditionResult(
type,
condition(type, architecture),
failDescription
)),
description
) { }

public OrderedArchitectureCondition(
Func<TRuleType, Architecture, bool> condition,
Func<TRuleType, Architecture, string> dynamicFailDescription,
string description
)
: base(
(ruleTypes, architecture) =>
ruleTypes.Select(type => new ConditionResult(
type,
condition(type, architecture),
dynamicFailDescription(type, architecture)
)),
description
) { }

public OrderedArchitectureCondition(
Func<TRuleType, Architecture, ConditionResult> condition,
string description
)
: base(
(ruleTypes, architecture) =>
ruleTypes.Select(type => condition(type, architecture)),
description
) { }

public OrderedArchitectureCondition(
Func<IEnumerable<TRuleType>, Architecture, IEnumerable<ConditionResult>> condition,
string description
)
: base(condition, description) { }
}
}
2 changes: 1 addition & 1 deletion ArchUnitNET/Fluent/Conditions/SimpleCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace ArchUnitNET.Fluent.Conditions
{
public class SimpleCondition<TRuleType> : ICondition<TRuleType>
public class SimpleCondition<TRuleType> : IOrderedCondition<TRuleType>
where TRuleType : ICanBeAnalyzed
{
private readonly Func<TRuleType, ConditionResult> _condition;
Expand Down
Loading