Skip to content

Commit 3c54c9b

Browse files
Optimize statusline
1 parent 78bcaa9 commit 3c54c9b

4 files changed

Lines changed: 122 additions & 67 deletions

File tree

‎src/PolygonClipper/PolygonClipper.cs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public Polygon Run()
231231
if (sweepEvent.Left)
232232
{
233233
// Insert the event into the status line and get neighbors
234-
int it = sweepEvent.PosSL = statusLine.Add(sweepEvent);
234+
int it = statusLine.Add(sweepEvent);
235235
prevEvent = statusLine.Prev(it);
236236
nextEvent = statusLine.Next(it);
237237

@@ -255,7 +255,8 @@ public Polygon Run()
255255
// Check intersection with the previous neighbor
256256
if (PossibleIntersection(prevEvent, sweepEvent, eventQueue, workspace) == 2)
257257
{
258-
SweepEvent? prevPrevEvent = statusLine.Prev(prevEvent.PosSL);
258+
int prevIndex = statusLine.IndexOf(prevEvent);
259+
SweepEvent? prevPrevEvent = statusLine.Prev(prevIndex);
259260
ComputeFields(prevEvent, prevPrevEvent, operation);
260261
ComputeFields(sweepEvent, prevEvent, operation);
261262
}
@@ -265,7 +266,7 @@ public Polygon Run()
265266
{
266267
// Remove the event from the status line
267268
sweepEvent = sweepEvent.OtherEvent;
268-
int it = sweepEvent.PosSL;
269+
int it = statusLine.IndexOf(sweepEvent);
269270
prevEvent = statusLine.Prev(it);
270271
nextEvent = statusLine.Next(it);
271272

‎src/PolygonClipper/StatusLine.cs‎

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public int Add(SweepEvent e)
8989
}
9090

9191
this.sortedEvents.Insert(index, e);
92-
this.Up(index);
92+
e.PosSL = index;
9393
return index;
9494
}
9595

@@ -102,9 +102,64 @@ public int Add(SweepEvent e)
102102
/// </exception>
103103
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104104
public void RemoveAt(int index)
105+
=> this.sortedEvents.RemoveAt(index);
106+
107+
/// <summary>
108+
/// Finds the current index of a sweep event in the status line.
109+
/// </summary>
110+
/// <param name="e">The event to locate.</param>
111+
/// <returns>The index of the event, or -1 if it is not present.</returns>
112+
public int IndexOf(SweepEvent e)
105113
{
106-
this.sortedEvents.RemoveAt(index);
107-
this.Down(index);
114+
List<SweepEvent> events = this.sortedEvents;
115+
int count = events.Count;
116+
int hint = e.PosSL;
117+
118+
if ((uint)hint < (uint)count && ReferenceEquals(events[hint], e))
119+
{
120+
return hint;
121+
}
122+
123+
int index = events.BinarySearch(e, this.comparer);
124+
if (index >= 0)
125+
{
126+
if (ReferenceEquals(events[index], e))
127+
{
128+
e.PosSL = index;
129+
return index;
130+
}
131+
132+
// BinarySearch can return any comparer-equal slot. Scan local ties by reference.
133+
for (int i = index - 1; i >= 0 && this.comparer.Compare(events[i], e) == 0; i--)
134+
{
135+
if (ReferenceEquals(events[i], e))
136+
{
137+
e.PosSL = i;
138+
return i;
139+
}
140+
}
141+
142+
for (int i = index + 1; i < count && this.comparer.Compare(events[i], e) == 0; i++)
143+
{
144+
if (ReferenceEquals(events[i], e))
145+
{
146+
e.PosSL = i;
147+
return i;
148+
}
149+
}
150+
}
151+
152+
// Fail-safe reference lookup for correctness if comparer order is temporarily unstable.
153+
for (int i = 0; i < count; i++)
154+
{
155+
if (ReferenceEquals(events[i], e))
156+
{
157+
e.PosSL = i;
158+
return i;
159+
}
160+
}
161+
162+
return -1;
108163
}
109164

110165
/// <summary>
@@ -138,24 +193,4 @@ public void RemoveAt(int index)
138193

139194
return null;
140195
}
141-
142-
private void Up(int index)
143-
{
144-
List<SweepEvent> e = this.sortedEvents;
145-
146-
for (int i = index + 1; i < e.Count; i++)
147-
{
148-
e[i].PosSL = i;
149-
}
150-
}
151-
152-
private void Down(int index)
153-
{
154-
List<SweepEvent> e = this.sortedEvents;
155-
156-
for (int i = index; i < e.Count; i++)
157-
{
158-
e[i].PosSL = i;
159-
}
160-
}
161196
}

‎tests/PolygonClipper.Benchmarks/Program.cs‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using BenchmarkDotNet.Columns;
5+
using BenchmarkDotNet.Configs;
6+
using BenchmarkDotNet.Exporters;
7+
using BenchmarkDotNet.Jobs;
8+
using BenchmarkDotNet.Loggers;
49
using BenchmarkDotNet.Running;
510

611
namespace SixLabors.PolygonClipper.Benchmarks;
@@ -10,5 +15,19 @@ internal sealed class Program
1015
public static void Main(string[] args)
1116
=> BenchmarkSwitcher
1217
.FromAssembly(typeof(Program).Assembly)
13-
.Run(args);
18+
.Run(args, new ShortRunConfig());
19+
}
20+
21+
public class ShortRunConfig : ManualConfig
22+
{
23+
public ShortRunConfig()
24+
{
25+
this.AddLogger(ConsoleLogger.Default);
26+
27+
this.AddColumnProvider(DefaultColumnProviders.Instance);
28+
29+
this.AddExporter(DefaultExporters.Html, DefaultExporters.Csv);
30+
31+
this.AddJob(Job.ShortRun);
32+
}
1433
}

‎tests/PolygonClipper.Benchmarks/StarBooleanBenches.cs‎

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -35,61 +35,61 @@ public void Setup()
3535
public Polygon PolygonClipperUnion()
3636
=> PolygonClipper.Union(this.subject, this.clipping);
3737

38-
[Benchmark]
39-
public PolyTreeD Clipper2Union()
40-
{
41-
ClipperD clipper = CreateClipper();
42-
clipper.AddSubject(this.clipperSubject);
43-
clipper.AddClip(this.clipperClipping);
44-
PolyTreeD solution = [];
45-
clipper.Execute(ClipType.Union, Clipper2Lib.FillRule.EvenOdd, solution);
46-
return solution;
47-
}
38+
//[Benchmark]
39+
//public PolyTreeD Clipper2Union()
40+
//{
41+
// ClipperD clipper = CreateClipper();
42+
// clipper.AddSubject(this.clipperSubject);
43+
// clipper.AddClip(this.clipperClipping);
44+
// PolyTreeD solution = [];
45+
// clipper.Execute(ClipType.Union, Clipper2Lib.FillRule.EvenOdd, solution);
46+
// return solution;
47+
//}
4848

4949
[Benchmark]
5050
public Polygon PolygonClipperIntersection()
5151
=> PolygonClipper.Intersection(this.subject, this.clipping);
5252

53-
[Benchmark]
54-
public PolyTreeD Clipper2Intersection()
55-
{
56-
ClipperD clipper = CreateClipper();
57-
clipper.AddSubject(this.clipperSubject);
58-
clipper.AddClip(this.clipperClipping);
59-
PolyTreeD solution = [];
60-
clipper.Execute(ClipType.Intersection, Clipper2Lib.FillRule.EvenOdd, solution);
61-
return solution;
62-
}
53+
//[Benchmark]
54+
//public PolyTreeD Clipper2Intersection()
55+
//{
56+
// ClipperD clipper = CreateClipper();
57+
// clipper.AddSubject(this.clipperSubject);
58+
// clipper.AddClip(this.clipperClipping);
59+
// PolyTreeD solution = [];
60+
// clipper.Execute(ClipType.Intersection, Clipper2Lib.FillRule.EvenOdd, solution);
61+
// return solution;
62+
//}
6363

6464
[Benchmark]
6565
public Polygon PolygonClipperDifference()
6666
=> PolygonClipper.Difference(this.subject, this.clipping);
6767

68-
[Benchmark]
69-
public PolyTreeD Clipper2Difference()
70-
{
71-
ClipperD clipper = CreateClipper();
72-
clipper.AddSubject(this.clipperSubject);
73-
clipper.AddClip(this.clipperClipping);
74-
PolyTreeD solution = [];
75-
clipper.Execute(ClipType.Difference, Clipper2Lib.FillRule.EvenOdd, solution);
76-
return solution;
77-
}
68+
//[Benchmark]
69+
//public PolyTreeD Clipper2Difference()
70+
//{
71+
// ClipperD clipper = CreateClipper();
72+
// clipper.AddSubject(this.clipperSubject);
73+
// clipper.AddClip(this.clipperClipping);
74+
// PolyTreeD solution = [];
75+
// clipper.Execute(ClipType.Difference, Clipper2Lib.FillRule.EvenOdd, solution);
76+
// return solution;
77+
//}
7878

7979
[Benchmark]
8080
public Polygon PolygonClipperXor()
8181
=> PolygonClipper.Xor(this.subject, this.clipping);
8282

83-
[Benchmark]
84-
public PolyTreeD Clipper2Xor()
85-
{
86-
ClipperD clipper = CreateClipper();
87-
clipper.AddSubject(this.clipperSubject);
88-
clipper.AddClip(this.clipperClipping);
89-
PolyTreeD solution = [];
90-
clipper.Execute(ClipType.Xor, Clipper2Lib.FillRule.EvenOdd, solution);
91-
return solution;
92-
}
83+
//[Benchmark]
84+
//public PolyTreeD Clipper2Xor()
85+
//{
86+
// ClipperD clipper = CreateClipper();
87+
// clipper.AddSubject(this.clipperSubject);
88+
// clipper.AddClip(this.clipperClipping);
89+
// PolyTreeD solution = [];
90+
// clipper.Execute(ClipType.Xor, Clipper2Lib.FillRule.EvenOdd, solution);
91+
// return solution;
92+
//}
9393

9494
private static ClipperD CreateClipper()
9595
=> new(ClipperPrecision)

0 commit comments

Comments
 (0)