11package com .kneelawk .graphlib .v3 .api .datastructure ;
22
3- import java . util . Objects ;
3+ import com . kneelawk . graphlib . v3 . api . pos . NodePos ;
44
55// Translated from 2xsaiko's HCTM-Base Graph code:
66// https://github.com/2xsaiko/hctm-base/blob/119df440743543b8b4979b450452d73f2c3c4c47/src/main/kotlin/common/graph/Graph.kt
1212 * upheld in this type's {@link #equals(Object)} and {@link #hashCode()}.
1313 * <p>
1414 * If a link needs to be directional, then its data should reference one of the nodes, making it asymmetrical.
15- * Referencing a node can be done with a {@link com.kneelawk.graphlib.v3.api.pos. NodePos}.
15+ * Referencing a node can be done with a {@link NodePos}.
1616 *
17- * @param first the first node in this link.
18- * @param second the second node in this link.
19- * @param key the key that makes this link unique out of all the links between the same two nodes.
20- * @param <K> the type of key used to index each node.
21- * @param <L> the type of link data contained in this link.
17+ * @param <K> the type of key used to index each node.
18+ * @param <V> the type of data contained in each node.
19+ * @param <LK> the type of link key that determines whether two links between the same nodes are unique.
20+ * @param <LV> the type of data contained in each link.
2221 */
23- public record KeyedLink <K , L >(KeyedNode <K , L > first , KeyedNode <K , L > second , L key ) {
22+ public final class KeyedLink <K , V , LK , LV > {
23+ private final KeyedNode <K , V , LK , LV > first ;
24+ private final KeyedNode <K , V , LK , LV > second ;
25+ private final Key <K , LK > key ;
26+ private final LV value ;
27+
28+ /**
29+ * Creates a new keyed link.
30+ *
31+ * @param first the first node in this link.
32+ * @param second the second node in this link.
33+ * @param key the key that describes this link uniquely.
34+ * @param value the value held within this link.
35+ */
36+ public KeyedLink (KeyedNode <K , V , LK , LV > first , KeyedNode <K , V , LK , LV > second , Key <K , LK > key , LV value ) {
37+ this .first = first ;
38+ this .second = second ;
39+ this .key = key ;
40+ this .value = value ;
41+
42+ if (!key .contains (first .key ()) || !key .contains (second .key ()))
43+ throw new IllegalArgumentException ("The link key must contain the keys of the link's two nodes" );
44+ }
45+
46+ /**
47+ * {@return the first node in this link}
48+ */
49+ public KeyedNode <K , V , LK , LV > first () {
50+ return first ;
51+ }
52+
53+ /**
54+ * {@return the second node in this link}
55+ */
56+ public KeyedNode <K , V , LK , LV > second () {
57+ return second ;
58+ }
59+
60+ /**
61+ * {@return this link's key}
62+ */
63+ public Key <K , LK > key () {
64+ return key ;
65+ }
66+
67+ /**
68+ * {@return this link's value}
69+ */
70+ public LV value () {
71+ return value ;
72+ }
73+
2474 /**
2575 * Checks to see if the given node is either of the two nodes in this link.
2676 *
2777 * @param node the node to check.
2878 * @return <code>true</code> if the given node is either of the nodes in this link.
2979 */
30- public boolean contains (KeyedNode <K , L > node ) {
31- return Objects . equals (first , node ) || Objects . equals (second , node );
80+ public boolean contains (KeyedNode <K , V , LK , LV > node ) {
81+ return first . key (). equals (node . key ()) || second . key (). equals (node . key () );
3282 }
3383
3484 /**
@@ -38,7 +88,7 @@ public boolean contains(KeyedNode<K, L> node) {
3888 * @return <code>true</code> if a node with the given key is wither of the nodes in this link.
3989 */
4090 public boolean contains (K key ) {
41- return Objects . equals ( first .key (), key ) || Objects . equals ( second .key (), key );
91+ return first .key (). equals ( key ) || second .key (). equals ( key );
4292 }
4393
4494 /**
@@ -47,8 +97,8 @@ public boolean contains(K key) {
4797 * @param node the node to get the other end of the link from.
4898 * @return the node at the other end of the link from the given node.
4999 */
50- public KeyedNode <K , L > other (KeyedNode <K , L > node ) {
51- if (Objects . equals (first , node )) {
100+ public KeyedNode <K , V , LK , LV > other (KeyedNode <K , V , LK , LV > node ) {
101+ if (first . key (). equals (node . key () )) {
52102 return second ;
53103 } else {
54104 return first ;
@@ -61,44 +111,104 @@ public KeyedNode<K, L> other(KeyedNode<K, L> node) {
61111 * @param key the key of the node to get the other end of hte link from.
62112 * @return the node at the other end of the link from the node with the given key.
63113 */
64- public KeyedNode <K , L > other (K key ) {
65- if (Objects . equals ( first .key (), key )) {
114+ public KeyedNode <K , V , LK , LV > other (K key ) {
115+ if (first .key (). equals ( key )) {
66116 return second ;
67117 } else {
68118 return first ;
69119 }
70120 }
71121
72- @ Override
73- public boolean equals (Object o ) {
74- if (this == o ) return true ;
75- if (o == null || getClass () != o .getClass ()) return false ;
76-
77- KeyedLink <?, ?> linkKey = (KeyedLink <?, ?>) o ;
78-
79- if (!key .equals (linkKey .key )) return false ;
80-
81- // note: hashCode and equals are symmetrical regardless of node order
82- if (first .equals (linkKey .first )) {
83- return second .equals (linkKey .second );
84- } else if (second .equals (linkKey .first )) {
85- return first .equals (linkKey .second );
86- }
122+ /**
123+ * Establishes this link between this link's two nodes.
124+ *
125+ * @return {@code true} if a link was successfully established, {@code} false if a link already existed with this link's key.
126+ */
127+ public boolean link () {
128+ return first .onLink (this ) == null & second .onLink (this ) == null ;
129+ }
87130
88- return false ;
131+ /**
132+ * Removes this link from the two nodes it is attached between.
133+ *
134+ * @return {@code true} if this link was connecting the two nodes to begin with.
135+ */
136+ public boolean unlink () {
137+ return first .onUnlink (key ) == this & second .onUnlink (key ) == this ;
89138 }
90139
91- @ Override
92- public int hashCode () {
93- // note: hashCode and equals are symmetrical regardless of node order
94- int result = first .hashCode ();
95- result = result ^ second .hashCode ();
96- result = 31 * result + key .hashCode ();
97- return result ;
140+ /**
141+ * {@return whether this link is connecting its two nodes}
142+ */
143+ public boolean isLinked () {
144+ return first .connections ().get (key ) == this && second .connections ().get (key ) == this ;
98145 }
99146
100147 @ Override
101148 public String toString () {
102149 return "link(" + first + " <-> " + second + ", " + key + ')' ;
103150 }
151+
152+ /**
153+ * Key used to index links.
154+ *
155+ * @param first the unique key of the first node.
156+ * @param second the unique key of the second node.
157+ * @param key the key that makes this link unique out of all the links between the same two nodes.
158+ * @param <N> the type of node key.
159+ * @param <L> the type of link key.
160+ */
161+ public record Key <N , L >(N first , N second , L key ) {
162+ /**
163+ * Gets whether this link key contains the given node key.
164+ *
165+ * @param nodeKey the node key to find.
166+ * @return {@code true} if this link key contains the given node key.
167+ */
168+ public boolean contains (N nodeKey ) {
169+ return first .equals (nodeKey ) || second .equals (nodeKey );
170+ }
171+
172+ /**
173+ * Gets the node key opposite the given node key.
174+ *
175+ * @param nodeKey the node key to get the opposite end of the link from.
176+ * @return the node key at the other end of the link.
177+ */
178+ public N other (N nodeKey ) {
179+ if (first .equals (nodeKey )) {
180+ return second ;
181+ } else {
182+ return first ;
183+ }
184+ }
185+
186+ @ Override
187+ public boolean equals (Object o ) {
188+ if (this == o ) return true ;
189+ if (o == null || getClass () != o .getClass ()) return false ;
190+
191+ Key <?, ?> linkKey = (Key <?, ?>) o ;
192+
193+ if (!key .equals (linkKey .key )) return false ;
194+
195+ // note: hashCode and equals are symmetrical regardless of node order
196+ if (first .equals (linkKey .first )) {
197+ return second .equals (linkKey .second );
198+ } else if (second .equals (linkKey .first )) {
199+ return first .equals (linkKey .second );
200+ }
201+
202+ return false ;
203+ }
204+
205+ @ Override
206+ public int hashCode () {
207+ // note: hashCode and equals are symmetrical regardless of node order
208+ int result = first .hashCode ();
209+ result = result ^ second .hashCode ();
210+ result = 31 * result + key .hashCode ();
211+ return result ;
212+ }
213+ }
104214}
0 commit comments