Intrusive Containers
Loading...
Searching...
No Matches
ManyMany.h
Go to the documentation of this file.
1/**
2@file ManyMany.h
3@brief Intrusive Many to Many Relationship.
4
5This file defines a trio of templates (ManyManyLinkRoot, ManyManyLinkLink, and ManyManyLinkNode)
6that implement a many-to-many interconnect web.
7
8@warning The ManyMany classes are new, and have not been extensively tested
9@bug The Locking implemented in the ManyMany containers is likely not sufficient yet.
10
11@copyright (c) 2014-2024 Richard Damon
12@parblock
13MIT License:
14
15Permission is hereby granted, free of charge, to any person obtaining a copy
16of this software and associated documentation files (the "Software"), to deal
17in the Software without restriction, including without limitation the rights
18to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19copies of the Software, and to permit persons to whom the Software is
20furnished to do so, subject to the following conditions:
21
22The above copyright notice and this permission notice shall be included in
23all copies or substantial portions of the Software.
24
25THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31THE SOFTWARE.
32@endparblock
33
34@par Overview
35@parblock
36ManyManyRoot, ManyManyNode and ManyManyLink (which acts as an intermediary) provide a simple API to allow classes to provide a
37basic Root <-> Node relationship where each Root can point to many nodes, and each node can be on many roots.
38
39To create this set of relationships, the ManyManyRoot and ManyManyNode classes create lists of ManyManyLink nodes that
40indicate each of those connections.
41
42The concept of "Root" and "Node" for this relationship is really arbitrary, but was chosen just to indicate the "sides" of the relationship in the links.
43
44To create this relationship, the class to act as the list derives from the template ListInRoot,
45and the class to act as the Node from ListInNode, both with a first parameter of the class name
46of the List class, and a second parameter of the Node class. There is an optional integral 3rd parameter
47to allow the classes to inherent from these multiple times if you need to represent multiple simultaneous
48relationships. This inheritance should be public, or you need to add templates as friends.
49
50At the point of declaration, both classes need to be declared, so you will typically have a forward of the other
51class before the definition of the class. At the point of usage of members, generally the full definition of both
52classes is needed to instance the code for the template.
53
54Inside this file, the following types have the following meanings:
55
56R: The "user" type that will be derived from ManyManyRoot
57
58N: The "user" type that will be derived from ManyManyNode
59
60L: The "user" type that will be derived from ManyManyLink.
61There is a version of ManyManyLink with L=void that allows the templates to use ManyManyLink<R, N, s, n, void> as the link class
62
63s: The ContainerThreadSafety value for the cluster. Defaults to no builtin safety (ContainerNoSafety)
64
65n: The integer parameter for the template to allow multiple usage
66
67Root: The particular instance of ManyManyRoot<R, N, s, n, L> being used
68
69Node: The particular instance of ManyManyNode<R, N, s, n, L> being used
70
71Link: The particular instance of ManyManyLink<R, N, s, n, L> being used
72
73node: will have type N*, to be used when walking the list.
74@endparblock
75
76@invariant
77@parblock
78
79 + R& root
80 + N& node
81 + L& link
82
83Mostly from DListInRoot and DListInNode
84
85 ManyManyRoot: (DListInRoot R -> L)
86 + if root.first() == nullptr
87 + root.last() == nullptr
88 + if root.first() !- nullptr
89 + root.last() != nullptr
90 + root.first()->root() == \&root
91 + root.first()->prev() == nullptr
92 + root.last()->root() == \&root
93 + root.last()->next() == nullptr
94
95 ManyManyNode: (DListInRoot: N -> L)
96 + if node.first() == nullptr
97 + node.last() == nullptr
98 + if node.first() !- nullptr
99 + node.last() != nullptr
100 + node.first()->root() == \&root
101 + node.first()->prev() == nullptr
102 + node.last()->root() == \&root
103 + node.last()->next() == nullptr
104
105 ManyManyLink: (DListInNode R->L, N->L)
106 + if link.root() == nullptr
107 + link.node() == nullptr // we point to both or neither
108 + link.nextRoot() == nullptr
109 + link.prevRoot() == nullptr
110 + link.nextNode() == nullptr
111 + link.prevNode() == nullptr
112
113 + if link.prevRoot() == nullptr
114 + link.root()->first() = \&link;
115 + if link.prevRoot() !- nullptr
116 + link.prevRoot()->root() == link.root()
117 + link.prevRoot()->nextRoot() == \&link
118 + if link.nextRoot() == nullptr
119 + link.root()->last() = \&link
120 + if link.nextRoot() != nullptr
121 + link.nextRoot()->root() == link.root()
122 + link.nextRoot()->prevRoot() == \&link
123
124 + if link.prevNode() == nullptr
125 + link.node()->first() = \&link;
126 + if link.prevNode() !- nullptr
127 + link.prevNode()->node() == link.node()
128 + link.prevNode()->nextNode() == \&link
129 + if link.nextNode() == nullptr
130 + link.node()->last() = \&link
131 + if link.nextNode() != nullptr
132 + link.nextNode()->node() == link.node()
133 + link.nextNode()->prevNode() == \&link
134@endparblock
135
136@ingroup IntrusiveContainers
137
138*/
139
140
141#ifndef CONTAINERS_MANYMANY_H
142#define CONTAINERS_MANYMANY_H
143
144#include "Container.h"
145
146#include "DListIn.h"
147
148template <class R, class N, ContainerThreadSafety s, int n, class L> class ManyManyLink;
149template <class R, class N, ContainerThreadSafety s = ContainerNoSafety, int n = 0, class L = ManyManyLink<R, N, s, n, void>> class ManyManyLink;
150template <class R, class N, ContainerThreadSafety s = ContainerNoSafety, int n = 0, class L = ManyManyLink<R, N, s, n, void>> class ManyManyRoot;
151template <class R, class N, ContainerThreadSafety s = ContainerNoSafety, int n = 0, class L = ManyManyLink<R, N, s, n, void>> class ManyManyNode;
152
153/**
154 * Root side of a many-many relationship
155 *
156 *
157@invariant
158@parblock
159From DListInRoot:
160 + if first() == nullptr
161 + last() == nullptr
162 + if first() !- nullptr
163 + last() != nullptr
164 + first()->root() == thiw
165 + first()->prev() == nullptr
166 + last()->root() == this
167 + last()->next() == nullptr
168@endparblock
169 * @ingroup IntrusiveContainers
170 */
171template <class R, class N, ContainerThreadSafety s, int n, class L> class ManyManyRoot : public DListInRoot<R, L, s, 2*n> {
172 typedef class ManyManyRoot<R, N, s, n, L> Root;
173 typedef class ManyManyNode<R, N, s, n, L> Node;
174 typedef class ManyManyLink<R, N, s, n, L> Link;
175 typedef class DListInRoot<R, L, s, 2*n> Base;
176
177 friend Node;
178 friend Link;
179public:
180 ManyManyRoot(N* node = nullptr, L* link = nullptr);
182 // 4 version of each to allow mixing and matching of pointers and references
183 void add(N& node, L& link);
184 void add(N& node, L* link = nullptr);
185 void add(N* node, L& link);
186 void add(N* node, L* link = nullptr);
187 void addFirst(N& node, L& link);
188 void addFirst(N& node, L* link = nullptr);
189 void addFirst(N* node, L& link);
190 void addFirst(N* node, L* link = nullptr);
191 void addLast(N& node, L& link);
192 void addLast(N& node, L* link = nullptr);
193 void addLast(N* node, L& link);
194 void addLast(N* node, L* link = nullptr);
195
196
197 bool remove(N& node);
198 bool remove(N* node);
199
200 L* first() const {return Base::first();}
201 L* last() const { return Base::last(); }
202
203 bool check() const override { return Base::check(); }
204
205 // Critical Sections used to Update the Container
206 unsigned writeLock() const { return Container<s>::writeLock(); }
207 void writeUnlock(unsigned save) const { Container<s>::writeUnlock(save); }
208 // Critical Section used to Read/Search the Container
209 unsigned readLock() const { return Container<s>::readLock(); }
210 void readUnlock(unsigned save) const { Container<s>::readUnlock(save);}
211};
212/**
213 * Node side of a many-many relationship
214 *
215@invariant
216@parblock
217From DListInRoot:
218 + if first() == nullptr
219 + last() == nullptr
220 + if first() !- nullptr
221 + last() != nullptr
222 + first()->root() == thiw
223 + first()->prev() == nullptr
224 + last()->root() == this
225 + last()->next() == nullptr
226@endparblock
227
228 * @ingroup IntrusiveContainers
229 */
230template <class R, class N, ContainerThreadSafety s, int n, class L> class ManyManyNode : public DListInRoot<N, L, s, 2*n+1> {
231 typedef class ManyManyRoot<R, N, s, n, L> Root;
232 typedef class ManyManyNode<R, N, s, n, L> Node;
233 typedef class ManyManyLink<R, N, s, n, L> Link;
234 typedef class DListInRoot<N, L, s, 2*n+1> Base;
235
236 friend Root;
237 friend Link;
238public:
239 ManyManyNode(R* root = nullptr, L* link = nullptr);
241
242 void add(R& root, L* link = nullptr);
243 void add(R* root, L* link = nullptr);
244 void addFirst(R& root, L* link = nullptr);
245 void addFirst(R* root, L* link = nullptr);
246 void addLast(R& root, L* link = nullptr);
247 void addLast(R* root, L* link = nullptr);
248
249 void add(R& root, L& link);
250 void add(R* root, L& link);
251 void addFirst(R& root, L& link);
252 void addFirst(R* root, L& link);
253 void addLast(R& root, L& link);
254 void addLast(R* root, L& link);
255
256 bool remove(R& node);
257 bool remove(R* node);
258
259 L* first() const {return Base::first();}
260 L* last() const { return Base::last(); }
261
262 bool check() const override { return Base::check(); }
263
264 // Critical Sections used to Update the Container
265 unsigned writeLock() const { return Container<s>::writeLock(); }
266 void writeUnlock(unsigned save) const { Container<s>::writeUnlock(save); }
267 // Critical Section used to Read/Search the Container
268 unsigned readLock() const { return Container<s>::readLock(); }
269 void readUnlock(unsigned save) const { Container<s>::readUnlock(save);}
270};
271
272/**
273 * Intermediate Link for a many-many relationship
274 *
275 * Allowed to be pointing to a user class to allow properties on the relationship.
276 *
277@invariant
278@parblock
279From DListInNode:
280 + if root() == nullptr
281 + node() == nullptr // we point to both or neither
282 + nextRoot() == nullptr
283 + prevRoot() == nullptr
284 + nextNode() == nullptr
285 + prevNode() == nullptr
286
287 + if prevRoot() == nullptr
288 + root()->first() = this;
289 + if prevRoot() !- nullptr
290 + prevRoot()->root() == root()
291 + prevRoot()->nextRoot() == this
292 + if nextRoot() == nullptr
293 + root()->last() = this
294 + if nextRoot() != nullptr
295 + nextRoot()->root() == link.root()
296 + nextRoot()->prevRoot() == this
297
298 + if link.prevNode() == nullptr
299 + node()->first() = this
300 + if prevNode() !- nullptr
301 + prevNode()->node() == link.node()
302 + prevNode()->nextNode() == this
303 + if nextNode() == nullptr
304 + node()->last() = this
305 + if nextNode() != nullptr
306 + nextNode()->node() == node()
307 + nextNode()->prevNode() == this
308@endparblock
309 * @ingroup IntrusiveContainers
310 */
311template <class R, class N, ContainerThreadSafety s, int n, class L> class ManyManyLink : public DListInNode<R, L, s, 2*n>, public DListInNode<N, L, s, 2*n+1> {
312 typedef class ManyManyRoot<R, N, s, n, L> Root;
313 typedef class ManyManyNode<R, N, s, n, L> Node;
314 typedef class ManyManyLink<R, N, s, n, L> Link;
315 typedef class DListInNode<R, L, s, 2*n> BaseRoot;
316 typedef class DListInNode<N, L, s, 2*n+1> BaseNode;
317 typedef class DListInRoot<R, L, s, 2*n> RootRoot;
318 typedef class DListInRoot<N, L, s, 2*n+1> RootNode;
319
320 friend Node;
321 friend Root;
322public:
323 ManyManyLink(R* root = nullptr, N* node = nullptr, L* link1 = nullptr, L* link2 = nullptr);
324 virtual ~ManyManyLink();
325
326 R* root() const { return BaseRoot::root(); }
327 N* node() const { return BaseNode::root(); }
328 L* prevRoot() const { return BaseRoot::prev(); }
329 L* nextRoot() const { return BaseRoot::next(); }
330 L* prevNode() const { return BaseNode::prev(); }
331 L* nextNode() const { return BaseNode::next(); }
332
333 void add(R* root, N* node, L* link1 = nullptr, L* link2 = nullptr);
334 void add(R& root, N& node);
335 void remove();
336
337 bool check() const override;
338
339private:
340 static L& getLink(L* link);
341
342 bool m_dynamic = false;
343};
344
345/**
346 * Default ManyManyLink final class if user has no need to add behaviors.
347 */
348template <class R, class N, ContainerThreadSafety s, int n> class ManyManyLink<R, N, s, n, void> : public ManyManyLink<R, N, s, n, ManyManyLink<R, N, s, n, void> > {
349public:
350};
351
352#endif // CONTAINERS_MANYMANY_H
Intrusive Container Documentation and Base Class.
Intrusive Double Linked List.
unsigned writeLock(bool upgrade) const
Obtain a write lock.
unsigned readLock(bool upgradable) const
Obtain a read lock.
void readUnlock(unsigned code) const
Release the read lock that was held.
void writeUnlock(unsigned code) const
Release write lock.
Intrusive Doubly Linked List, Node.
Definition DListIn.h:204
Intrusive Doubly Linked List, List.
Definition DListIn.h:137
Node side of a many-many relationship.
Definition ManyMany.h:230
class DListInRoot< N, L, s, 2 *n+1 > Base
Definition ManyMany.h:234
void addLast(R &root, L *link=nullptr)
Definition ManyMany.hpp:269
class ManyManyNode< R, N, s, n, L > Node
Definition ManyMany.h:232
L * last() const
Definition ManyMany.h:260
bool check() const override
Check a DListInRoot and the list connected.
Definition ManyMany.h:262
ManyManyNode(R *root=nullptr, L *link=nullptr)
Definition ManyMany.hpp:205
~ManyManyNode()
Definition ManyMany.hpp:212
void addFirst(R &root, L *link=nullptr)
Definition ManyMany.hpp:248
friend Link
Definition ManyMany.h:237
class ManyManyLink< R, N, s, n, L > Link
Definition ManyMany.h:233
unsigned readLock() const
Definition ManyMany.h:268
unsigned writeLock() const
Definition ManyMany.h:265
class ManyManyRoot< R, N, s, n, L > Root
Definition ManyMany.h:231
bool remove(R &node)
Definition ManyMany.hpp:279
void readUnlock(unsigned save) const
Definition ManyMany.h:269
void add(R &root, L *link=nullptr)
Definition ManyMany.hpp:227
friend Root
Definition ManyMany.h:236
L * first() const
Definition ManyMany.h:259
void writeUnlock(unsigned save) const
Definition ManyMany.h:266
Root side of a many-many relationship.
Definition ManyMany.h:171
bool check() const override
Check a DListInRoot and the list connected.
Definition ManyMany.h:203
class ManyManyLink< R, N, s, n, L > Link
Definition ManyMany.h:174
class ManyManyNode< R, N, s, n, L > Node
Definition ManyMany.h:173
ManyManyRoot(N *node=nullptr, L *link=nullptr)
Definition ManyMany.hpp:76
void writeUnlock(unsigned save) const
Definition ManyMany.h:207
void readUnlock(unsigned save) const
Definition ManyMany.h:210
bool remove(N &node)
Remove Node for list.
Definition ManyMany.hpp:170
class ManyManyRoot< R, N, s, n, L > Root
Definition ManyMany.h:172
unsigned readLock() const
Definition ManyMany.h:209
friend Node
Definition ManyMany.h:177
void add(N &node, L &link)
Remove Node for list.
Definition ManyMany.hpp:98
L * first() const
Definition ManyMany.h:200
L * last() const
Definition ManyMany.h:201
void addFirst(N &node, L &link)
Definition ManyMany.hpp:118
~ManyManyRoot()
Definition ManyMany.hpp:83
unsigned writeLock() const
Definition ManyMany.h:206
class DListInRoot< R, L, s, 2 *n > Base
Definition ManyMany.h:175
friend Link
Definition ManyMany.h:178
void addLast(N &node, L &link)
Definition ManyMany.hpp:139