< Summary

Information
Class: Gravitas.IslandGraphUtility
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/IslandGraphUtility.cs
Line coverage
100%
Covered lines: 78
Uncovered lines: 0
Coverable lines: 78
Total lines: 177
Line coverage: 100%
Branch coverage
100%
Covered branches: 44
Total branches: 44
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
SortAndDeduplicate(...)100%1010100%
Find(...)100%66100%
Union(...)100%66100%
FindRoot(...)100%44100%
CompressRoots(...)100%22100%
ResolveConstraintRootKey(...)100%44100%
WakeBodies(...)100%1212100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/IslandGraphUtility.cs

#LineLine coverage
 1//=======================================================================
 2// IslandGraphUtility.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using SwiftCollections;
 9using System.Collections.Generic;
 10
 11namespace Gravitas;
 12
 13internal interface IIslandNodeState
 14{
 15    int BodyKey { get; }
 16
 17    int ParentIndex { get; set; }
 18
 19    int RootKey { get; set; }
 20
 21    bool IsAwakeForCollision { get; }
 22
 23    void WakeFromCollision();
 24}
 25
 26internal sealed class IslandNodeKeyComparer<TNode> : IComparer<TNode>
 27    where TNode : struct, IIslandNodeState
 28{
 29    public int Compare(TNode left, TNode right) =>
 30        left.BodyKey.CompareTo(right.BodyKey);
 31}
 32
 33internal static class IslandGraphUtility
 34{
 35    public static void SortAndDeduplicate<TNode>(SwiftList<TNode> nodes, IComparer<TNode> comparer)
 36        where TNode : struct, IIslandNodeState
 37    {
 112438        if (nodes.Count == 0)
 339            return;
 40
 112141        if (nodes.Count == 1)
 42        {
 11343            TNode singleNode = nodes[0];
 11344            singleNode.ParentIndex = 0;
 11345            singleNode.RootKey = singleNode.BodyKey;
 11346            nodes[0] = singleNode;
 11347            return;
 48        }
 49
 100850        nodes.SortInPlace(comparer);
 51
 100852        int writeIndex = 0;
 100853        int previousKey = -1;
 2581654        for (int readIndex = 0; readIndex < nodes.Count; readIndex++)
 55        {
 1190056            TNode node = nodes[readIndex];
 1190057            if (node.BodyKey == previousKey)
 58                continue;
 59
 621760            node.ParentIndex = writeIndex;
 621761            node.RootKey = node.BodyKey;
 621762            nodes[writeIndex++] = node;
 621763            previousKey = node.BodyKey;
 64        }
 65
 669166        while (nodes.Count > writeIndex)
 568367            nodes.RemoveAt(nodes.Count - 1);
 100868    }
 69
 70    public static int Find<TNode>(SwiftList<TNode> nodes, int key)
 71        where TNode : struct, IIslandNodeState
 72    {
 2402273        int low = 0;
 2402274        int high = nodes.Count - 1;
 6092675        while (low <= high)
 76        {
 6092577            int mid = low + ((high - low) >> 1);
 6092578            int midKey = nodes[mid].BodyKey;
 6092579            if (midKey == key)
 2402180                return mid;
 81
 3690482            if (midKey < key)
 2018183                low = mid + 1;
 84            else
 1672385                high = mid - 1;
 86        }
 87
 188        return -1;
 89    }
 90
 91    public static void Union<TNode>(SwiftList<TNode> nodes, int nodeA, int nodeB)
 92        where TNode : struct, IIslandNodeState
 93    {
 558094        int rootA = FindRoot(nodes, nodeA);
 558095        int rootB = FindRoot(nodes, nodeB);
 558096        if (rootA == rootB)
 73197            return;
 98
 484999        int keyA = nodes[rootA].BodyKey;
 4849100        int keyB = nodes[rootB].BodyKey;
 4849101        int parent = keyA <= keyB ? rootA : rootB;
 4849102        int child = parent == rootA ? rootB : rootA;
 103
 4849104        TNode childNode = nodes[child];
 4849105        childNode.ParentIndex = parent;
 4849106        childNode.RootKey = nodes[parent].BodyKey;
 4849107        nodes[child] = childNode;
 4849108    }
 109
 110    public static int FindRoot<TNode>(SwiftList<TNode> nodes, int index)
 111        where TNode : struct, IIslandNodeState
 112    {
 17490113        int root = index;
 26494114        while (nodes[root].ParentIndex != root)
 9004115            root = nodes[root].ParentIndex;
 116
 26494117        while (index != root)
 118        {
 9004119            TNode node = nodes[index];
 9004120            int parent = node.ParentIndex;
 9004121            node.ParentIndex = root;
 9004122            node.RootKey = nodes[root].BodyKey;
 9004123            nodes[index] = node;
 9004124            index = parent;
 125        }
 126
 17490127        return root;
 128    }
 129
 130    public static void CompressRoots<TNode>(SwiftList<TNode> nodes)
 131        where TNode : struct, IIslandNodeState
 132    {
 14902133        for (int i = 0; i < nodes.Count; i++)
 134        {
 6330135            int root = FindRoot(nodes, i);
 6330136            TNode node = nodes[i];
 6330137            node.RootKey = nodes[root].BodyKey;
 6330138            nodes[i] = node;
 139        }
 1121140    }
 141
 142    public static int ResolveConstraintRootKey<TNode>(SwiftList<TNode> nodes, int nodeA, int nodeB)
 143        where TNode : struct, IIslandNodeState
 144    {
 6415145        if (nodeA >= 0)
 5976146            return nodes[nodeA].RootKey;
 147
 439148        return nodeB >= 0 ? nodes[nodeB].RootKey : -1;
 149    }
 150
 151    public static bool WakeBodies<TNode>(SwiftList<TNode> nodes, int rootKey)
 152        where TNode : struct, IIslandNodeState
 153    {
 1463154        bool hasAwakeBody = false;
 21176155        for (int i = 0; i < nodes.Count; i++)
 156        {
 10583157            TNode node = nodes[i];
 10583158            if (node.RootKey == rootKey && node.IsAwakeForCollision)
 159            {
 1458160                hasAwakeBody = true;
 1458161                break;
 162            }
 163        }
 164
 1463165        if (!hasAwakeBody)
 5166            return false;
 167
 51936168        for (int i = 0; i < nodes.Count; i++)
 169        {
 24510170            TNode node = nodes[i];
 24510171            if (node.RootKey == rootKey)
 6305172                node.WakeFromCollision();
 173        }
 174
 1458175        return true;
 176    }
 177}