Skip to content

Commit cb83e98

Browse files
authored
Merge pull request #433 from TNG/feat/add-iorderedcondition
Add IOrderedCondition
2 parents 8859557 + caf2655 commit cb83e98

File tree

10 files changed

+338
-274
lines changed

10 files changed

+338
-274
lines changed

ArchUnitNET/Domain/Extensions/EnumerableExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,25 @@ Architecture architecture
6262
(arg.Item1, arg.Item2 is Type type ? architecture.GetITypeOfType(type) : arg.Item2)
6363
);
6464
}
65+
66+
/// <summary>
67+
/// Creates a lookup function for the given collection of elements.
68+
/// For smaller collections, it uses the Contains method of the collection directly.
69+
/// For larger collections, it creates a HashSet for O(1) average time complexity lookups.
70+
/// </summary>
71+
///
72+
/// <typeparam name="T">The type of elements in the collection.</typeparam>
73+
///
74+
/// <param name="elements">The collection of elements to create a lookup function for.</param>
75+
///
76+
/// <returns>A function that checks if an element is in the collection.</returns>
77+
public static Func<T, bool> CreateLookupFn<T>(ICollection<T> elements)
78+
{
79+
if (elements.Count < 20)
80+
{
81+
return elements.Contains;
82+
}
83+
return new HashSet<T>(elements).Contains;
84+
}
6585
}
6686
}

ArchUnitNET/Domain/UnavailableType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public override string ToString()
4242
return FullName;
4343
}
4444

45-
private bool Equals(Struct other)
45+
private bool Equals(UnavailableType other)
4646
{
4747
return Equals(Type, other.Type);
4848
}

ArchUnitNET/Fluent/ConditionManager.cs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,34 @@ ICanBeEvaluated archRuleCreator
106106
var filteredObjectsList = filteredObjects.ToList();
107107
if (filteredObjectsList.IsNullOrEmpty() && !CheckEmpty())
108108
{
109-
yield return new EvaluationResult(
110-
null,
111-
new StringIdentifier(""),
112-
false,
113-
"There are no objects matching the criteria",
114-
archRuleCreator,
115-
architecture
109+
return new[]
110+
{
111+
new EvaluationResult(
112+
null,
113+
new StringIdentifier(""),
114+
false,
115+
"There are no objects matching the criteria",
116+
archRuleCreator,
117+
architecture
118+
),
119+
};
120+
}
121+
122+
if (_conditionElements.All(e => e.IsOrdered()))
123+
{
124+
var conditionResults = _conditionElements
125+
.Select(conditionElement =>
126+
conditionElement.Check(filteredObjectsList, architecture).ToList()
127+
)
128+
.ToList();
129+
return filteredObjectsList.Select(
130+
(t, i) =>
131+
CreateEvaluationResult(
132+
conditionResults.Select(results => results[i]),
133+
architecture,
134+
archRuleCreator
135+
)
116136
);
117-
yield break;
118137
}
119138

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

132-
foreach (var t in filteredObjectsList)
133-
{
134-
yield return CreateEvaluationResult(
151+
return filteredObjectsList.Select(t =>
152+
CreateEvaluationResult(
135153
FindResultsForObject(conditionResults, t),
136154
architecture,
137155
archRuleCreator
138-
);
139-
}
156+
)
157+
);
140158
}
141159
else
142160
{
@@ -145,15 +163,13 @@ ICanBeEvaluated archRuleCreator
145163
conditionElement.Check(filteredObjectsList, architecture).ToList()
146164
)
147165
.ToList();
148-
149-
foreach (var t in filteredObjectsList)
150-
{
151-
yield return CreateEvaluationResult(
166+
return filteredObjectsList.Select(t =>
167+
CreateEvaluationResult(
152168
FindResultsForObject(conditionResults, t),
153169
architecture,
154170
archRuleCreator
155-
);
156-
}
171+
)
172+
);
157173
}
158174
}
159175

@@ -349,6 +365,11 @@ Architecture architecture
349365
.Select(result => new ConditionElementResult(result, _logicalConjunction));
350366
}
351367

368+
public bool IsOrdered()
369+
{
370+
return _condition is IOrderedCondition<T>;
371+
}
372+
352373
public bool CheckEmpty(bool currentResult)
353374
{
354375
if (_condition == null)

ArchUnitNET/Fluent/Conditions/ArchitectureCondition.cs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,6 @@ private readonly Func<
1414
IEnumerable<ConditionResult>
1515
> _condition;
1616

17-
public ArchitectureCondition(
18-
Func<TRuleType, Architecture, bool> condition,
19-
string description,
20-
string failDescription
21-
)
22-
{
23-
_condition = (ruleTypes, architecture) =>
24-
ruleTypes.Select(type => new ConditionResult(
25-
type,
26-
condition(type, architecture),
27-
failDescription
28-
));
29-
Description = description;
30-
}
31-
32-
public ArchitectureCondition(
33-
Func<TRuleType, Architecture, ConditionResult> condition,
34-
string description
35-
)
36-
{
37-
_condition = (ruleTypes, architecture) =>
38-
ruleTypes.Select(type => condition(type, architecture));
39-
Description = description;
40-
}
41-
4217
public ArchitectureCondition(
4318
Func<IEnumerable<TRuleType>, Architecture, IEnumerable<ConditionResult>> condition,
4419
string description
@@ -48,21 +23,6 @@ string description
4823
Description = description;
4924
}
5025

51-
public ArchitectureCondition(
52-
Func<TRuleType, Architecture, bool> condition,
53-
Func<TRuleType, Architecture, string> dynamicFailDescription,
54-
string description
55-
)
56-
{
57-
_condition = (ruleTypes, architecture) =>
58-
ruleTypes.Select(type => new ConditionResult(
59-
type,
60-
condition(type, architecture),
61-
dynamicFailDescription(type, architecture)
62-
));
63-
Description = description;
64-
}
65-
6626
public string Description { get; }
6727

6828
public IEnumerable<ConditionResult> Check(

ArchUnitNET/Fluent/Conditions/ExistsCondition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace ArchUnitNET.Fluent.Conditions
66
{
7-
public class ExistsCondition<TRuleType> : ICondition<TRuleType>
7+
public class ExistsCondition<TRuleType> : IOrderedCondition<TRuleType>
88
where TRuleType : ICanBeAnalyzed
99
{
1010
private readonly bool _valueIfExists;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
using ArchUnitNET.Domain;
2+
3+
namespace ArchUnitNET.Fluent.Conditions
4+
{
5+
public interface IOrderedCondition<in TRuleType> : ICondition<TRuleType>
6+
where TRuleType : ICanBeAnalyzed { }
7+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using ArchUnitNET.Domain;
5+
6+
namespace ArchUnitNET.Fluent.Conditions
7+
{
8+
public class OrderedArchitectureCondition<TRuleType>
9+
: ArchitectureCondition<TRuleType>,
10+
IOrderedCondition<TRuleType>
11+
where TRuleType : ICanBeAnalyzed
12+
{
13+
public OrderedArchitectureCondition(
14+
Func<TRuleType, Architecture, bool> condition,
15+
string description,
16+
string failDescription
17+
)
18+
: base(
19+
(ruleTypes, architecture) =>
20+
ruleTypes.Select(type => new ConditionResult(
21+
type,
22+
condition(type, architecture),
23+
failDescription
24+
)),
25+
description
26+
) { }
27+
28+
public OrderedArchitectureCondition(
29+
Func<TRuleType, Architecture, bool> condition,
30+
Func<TRuleType, Architecture, string> dynamicFailDescription,
31+
string description
32+
)
33+
: base(
34+
(ruleTypes, architecture) =>
35+
ruleTypes.Select(type => new ConditionResult(
36+
type,
37+
condition(type, architecture),
38+
dynamicFailDescription(type, architecture)
39+
)),
40+
description
41+
) { }
42+
43+
public OrderedArchitectureCondition(
44+
Func<TRuleType, Architecture, ConditionResult> condition,
45+
string description
46+
)
47+
: base(
48+
(ruleTypes, architecture) =>
49+
ruleTypes.Select(type => condition(type, architecture)),
50+
description
51+
) { }
52+
53+
public OrderedArchitectureCondition(
54+
Func<IEnumerable<TRuleType>, Architecture, IEnumerable<ConditionResult>> condition,
55+
string description
56+
)
57+
: base(condition, description) { }
58+
}
59+
}

ArchUnitNET/Fluent/Conditions/SimpleCondition.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace ArchUnitNET.Fluent.Conditions
77
{
8-
public class SimpleCondition<TRuleType> : ICondition<TRuleType>
8+
public class SimpleCondition<TRuleType> : IOrderedCondition<TRuleType>
99
where TRuleType : ICanBeAnalyzed
1010
{
1111
private readonly Func<TRuleType, ConditionResult> _condition;

0 commit comments

Comments
 (0)