-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRoutingTable.kt
141 lines (118 loc) · 4.23 KB
/
RoutingTable.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package core.routing
/**
* A RoutingTable is a data structure that associates neighbors to routes.
*
* A routing table stores an entry for each neighbor. Each entry stores a candidate route and a set
* of attributes. Currently, the only attribute supported is a flag indicating whether or not the
* corresponding neighbor was enabled or not.
*
* A routing table can hold a single type of route given by [R]. Given that different route
* implementations have different definitions for an invalid route, the routing table requires a
* [invalidRoute] to use as invalid route. The [invalidRoute] is assigned to a neighbor when the
* table does not hold any candidate route for that neighbor.
*
* By default, all neighbors are associated with the [invalidRoute] and are enabled.
*
* The routing table does not perform any selection operations over its routes. For that see
* [RouteSelector].
*
* @property invalidRoute the route to use as invalid route
* @property size the number of route entries stored in this routing table
*
* Created on 21-07-2017
*
* @author David Fialho
*/
class RoutingTable<R: Route> private constructor(
val invalidRoute: R,
private val routes: MutableMap<Node<R>, MutableEntry<R>> = HashMap()
) {
companion object Factory {
/**
* Returns a routing table without any entries. The route [invalid] will be used as the
* invalid route.
*/
fun <R: Route> empty(invalid: R) = RoutingTable(invalid)
/**
* Returns a routing table containing the specified [entries]. The route [invalid] will be
* used as the invalid route.
*/
fun <R: Route> of(invalid: R, vararg entries: Entry<R>): RoutingTable<R> {
val routes = HashMap<Node<R>, MutableEntry<R>>(entries.size)
for ((neighbor, route, enabled) in entries) {
routes.put(neighbor, MutableEntry(route, enabled))
}
return RoutingTable(invalid, routes)
}
}
/**
* Returns the number of entries in the table.
*/
val size: Int get() = routes.size
/**
* Entries that are actually stored. Entries need to mutable for the table to update its
* attributes individually.
*/
data class MutableEntry<R>(var route: R, var enabled: Boolean = true)
/**
* Represents an entry in the routing table.
*/
data class Entry<R: Route>(val neighbor: Node<R>, val route: R, val enabled: Boolean = true)
/**
* Returns the candidate route stored for [neighbor].
*/
operator fun get(neighbor: Node<R>): R {
return routes[neighbor]?.route ?: invalidRoute
}
/**
* Sets the candidate route for [neighbor].
*/
operator fun set(neighbor: Node<R>, route: R) {
val entry = routes[neighbor]
if (entry == null) {
// It is a new neighbor - create a new entry
routes[neighbor] = MutableEntry(route)
} else {
// Update the existing entry
entry.route = route
}
}
/**
* Clears all entries from the table. All neighbors are enabled and assigned the [invalidRoute].
*/
fun clear() {
routes.clear()
}
/**
* Sets the enable/disable flag for [neighbor], according to [enabled].
*
* @return the candidate route for [neighbor]
*/
fun setEnabled(neighbor: Node<R>, enabled: Boolean): R {
val entry = routes[neighbor]
return if (entry == null) {
routes[neighbor] = MutableEntry(invalidRoute, enabled = false)
invalidRoute
} else {
entry.enabled = enabled
entry.route
}
}
/**
* Checks whether or not [neighbor] is enabled. By default, a neighbor is enabled.
*/
fun isEnabled(neighbor: Node<R>): Boolean {
return routes[neighbor]?.enabled ?: return true
}
/**
* Applies [operation] to each entry in this routing table.
*/
inline internal fun forEach(operation: (Node<R>, R, Boolean) -> Unit) {
for ((neighbor, entry) in routes) {
operation(neighbor, entry.route, entry.enabled)
}
}
override fun toString(): String {
return "RoutingTable(routes=$routes)"
}
}