aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
indexedTree_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
49
50// to ease IDE parser
52
53namespace gum {
54 /* =========================================================================*/
55 /* =========================================================================*/
56 /* === IMPLEMENTATION OF NODES FOR GENERIC TREE (DATA) STRUCTURE === */
57 /* =========================================================================*/
58 /* =========================================================================*/
59
60 // creates a tree with one node (with or without data)
61
62 template < typename Key, typename Data >
63 IndexedTree< Key, Data >::IndexedTree(const Key& theKey, Data* theData) :
64 key(theKey), data(theData), parent(0) {
65 // for debugging purposes
66 GUM_CONSTRUCTOR(IndexedTree);
67 }
68
69 // creates a tree with one node (with or without data)
70
71 template < typename Key, typename Data >
72 IndexedTree< Key, Data >::IndexedTree(Data* theData) : data(theData), parent(0) {
73 // for debugging purposes
74 GUM_CONSTRUCTOR(IndexedTree);
75 }
76
77 // creates a tree with one node with data
78
79 template < typename Key, typename Data >
80 IndexedTree< Key, Data >::IndexedTree(const Key& theKey, const Data& theData) :
81 key(theKey), data(new Data(theData)), parent(0) {
82 // for debugging purposes
83 GUM_CONSTRUCTOR(IndexedTree);
84 }
85
86 // copy constructor
87
88 template < typename Key, typename Data >
90 key(from.key), data(0), parent(0) {
91 // for debugging purposes
92 GUM_CONS_CPY(IndexedTree);
93
94 try {
95 // create the data of the node
96 if (from.data) data = new Data(*from.data);
97
98 // create and link properly the children
99 children = from.children;
100
101 for (HashTableIteratorSafe< Key, IndexedTree< Key, Data > > iter = children.begin();
102 iter != children.end();
103 ++iter)
104 iter->parent = this;
105 } catch (...) {
106 if (data) delete data;
107
108 children.clear();
109
110 throw;
111 }
112 }
113
114 // copy operator
115
116 template < typename Key, typename Data >
119 // avoid self assignment
120 if (this != &from) {
121 // for debugging purposes
122 GUM_OP_CPY(IndexedTree);
123
124 try {
125 key = from.key;
126
127 if (data) delete data;
128
129 if (from.data) data = new Data(*from.data);
130 else data = 0;
131
132 children = from.children;
133
134 for (HashTableIteratorSafe< Key, IndexedTree< Key, Data > > iter = children.begin();
135 iter != children.end();
136 ++iter)
137 iter->parent = this;
138 } catch (...) {
139 if (data) delete data;
140
141 children.clear();
142
143 throw;
144 }
145 }
146
147 return *this;
148 }
149
150 // destructor
151
152 template < typename Key, typename Data >
154 // for debugging purposes
155 GUM_DESTRUCTOR(IndexedTree);
156
157 if (data) delete data;
158 }
159
160 // adds a new node into the tree
161
162 template < typename Key, typename Data >
163 void IndexedTree< Key, Data >::insertNode(const std::vector< Key >& index, const Data* theData) {
164 // parse the tree until we are on the proper index. Then, insert the new
165 // node.
166 // current_node is a pointer on the node of the tree corresponding to
167 // position
168 // i in vector index. When i+2 < index.size(), we need go down into the tree
169 // structure before we can insert the new node
170 IndexedTree< Key, Data >* current_node = this;
171 unsigned int i;
172
173 for (i = 0; i + 1 < index.size(); ++i) {
174 // if the node that should be on the path between the root of the tree and
175 // the node that we wish to insert does not exist, create it
176 if (!children.exists(index[i])) {
177 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
178 current_node->children.insert(index[i], new_node);
179 new_node->parent = this;
180 current_node = new_node;
181 } else current_node = current_node->children[index[i]];
182 }
183
184 // here, we can insert the new node. if ind + 1 == index.size(), this means
185 // that
186 // the index vector was not empty, else the vector was empty and we are at
187 // the
188 // root of the tree
189 if (i + 1 == index.size()) {
190 // if the node to be inserted already exist, throw an exception
191 if (current_node->children.exists(index[i])) {
192 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
193 }
194
195 // here, the node to be inserted does not exist, so we must create it
197 = new IndexedTree< Key, Data >(index[i], const_cast< Data* >(theData));
198
199 current_node->children.insert(index[i], new_node);
200
201 new_node->parent = current_node;
202 } else {
203 // here, the node to be inserted is the root of the tree (so it already
204 // exists)
205 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
206 }
207 }
208
209 // adds a new node into the tree
210
211 template < typename Key, typename Data >
212 void IndexedTree< Key, Data >::insertNode(const std::vector< Key >& index, const Data& theData) {
213 // parse the tree until we are on the proper index. Then, insert the new
214 // node.
215 // current_node is a pointer on the node of the tree corresponding to
216 // position
217 // i in vector index. When i+2 < index.size(), we need go down into the tree
218 // structure before we can insert the new node
219 IndexedTree< Key, Data >* current_node = this;
220 unsigned int i;
221
222 for (i = 0; i + 1 < index.size(); ++i) {
223 // if the node that should be on the path between the root of the tree and
224 // the node that we wish to insert does not exist, create it
225 if (!children.exists(index[i])) {
226 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
227 current_node->children.insert(index[i], new_node);
228 new_node->parent = this;
229 current_node = new_node;
230 } else current_node = current_node->children[index[i]];
231 }
232
233 // here, we can insert the new node. if ind + 1 == index.size(), this means
234 // that
235 // the index vector was not empty, else the vector was empty and we are at
236 // the
237 // root of the tree
238 if (i + 1 == index.size()) {
239 // if the node to be inserted already exist, throw an exception
240 if (current_node->children.exists(index[i])) {
241 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
242 }
243
244 // here, the node to be inserted does not exist, so we must create it
245 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
246
247 current_node->children.insert(index[i], new_node);
248
249 new_node->parent = current_node;
250 } else {
251 // here, the node to be inserted is the root of the tree (so it already
252 // exists)
253 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
254 }
255 }
256
257 // updates the value of a node (or adds it if it does not already exist)
258
259 template < typename Key, typename Data >
260 void IndexedTree< Key, Data >::setNode(const std::vector< Key >& index, Data* theData) {
261 // parse the tree until we are on the proper index. Then, insert the new
262 // node.
263 // current_node is a pointer on the node of the tree corresponding to
264 // position
265 // i in vector index. When i+2 < index.size(), we need go down into the tree
266 // structure before we can insert the new node
267 IndexedTree< Key, Data >* current_node = this;
268 unsigned int i;
269
270 for (i = 0; i + 1 < index.size(); ++i) {
271 // if the node that should be on the path between the root of the tree and
272 // the node that we wish to insert does not exist, create it
273 if (!children.exists(index[i])) {
274 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
275 current_node->children.insert(index[i], new_node);
276 new_node->parent = this;
277 current_node = new_node;
278 } else current_node = current_node->children[index[i]];
279 }
280
281 // here, we can set the new node. if ind + 1 == index.size(), this means
282 // that
283 // the index vector was not empty, else the vector was empty and we are at
284 // the
285 // root of the tree
286 if (i + 1 == index.size()) {
287 // if the node to be set does not exist, create it, else modify it
288 if (current_node->children.exists(index[i])) {
289 IndexedTree< Key, Data >* node = current_node->children[index[i]];
290
291 if (node->data) delete node->data;
292
293 node->data = theData;
294 } else {
295 // here, the node tobe set does not exist, so we must create it
296 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
297 current_node->children.insert(index[i], new_node);
298 new_node->parent = current_node;
299 }
300 } else {
301 // here, the node to be set is the root of the tree (so it does already
302 // exist
303 if (data) delete data;
304
305 data = theData;
306 }
307 }
308
309 // updates the value of a node (or adds it if it does not already exist)
310
311 template < typename Key, typename Data >
312 void IndexedTree< Key, Data >::setNode(const std::vector< Key >& index, const Data& theData) {
313 // parse the tree until we are on the proper index. Then, insert the new
314 // node.
315 // current_node is a pointer on the node of the tree corresponding to
316 // position
317 // i in vector index. When i+2 < index.size(), we need go down into the tree
318 // structure before we can insert the new node
319 IndexedTree< Key, Data >* current_node = this;
320 unsigned int i;
321
322 for (i = 0; i + 1 < index.size(); ++i) {
323 // if the node that should be on the path between the root of the tree and
324 // the node that we wish to insert does not exist, create it
325 if (!children.exists(index[i])) {
326 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
327 current_node->children.insert(index[i], new_node);
328 new_node->parent = this;
329 current_node = new_node;
330 } else current_node = current_node->children[index[i]];
331 }
332
333 // here, we can set the new node. if ind + 1 == index.size(), this means
334 // that
335 // the index vector was not empty, else the vector was empty and we are at
336 // the
337 // root of the tree
338 if (i + 1 == index.size()) {
339 // if the node to be set does not exist, create it, else modify it
340 if (current_node->children.exists(index[i])) {
341 IndexedTree< Key, Data >* node = current_node->children[index[i]];
342
343 if (node->data) delete node->data;
344
345 node->data = new Data(theData);
346 } else {
347 // here, the node tobe set does not exist, so we must create it
348 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
349 current_node->children.insert(index[i], new_node);
350 new_node->parent = current_node;
351 }
352 } else {
353 // here, the node to be set is the root of the tree (so it does already
354 // exist
355 if (data) delete data;
356
357 data = new Data(theData);
358 }
359 }
360
361 // returns the value of a given test from the cache
362
363 template < typename Key, typename Data >
364 INLINE Data& IndexedTree< Key, Data >::getData(const std::vector< Key >& index) const {
365 IndexedTree< Key, Data >* current_node = const_cast< IndexedTree< Key, Data >* >(this);
366
367 for (unsigned int i = 0; i < index.size(); ++i)
368 current_node = current_node->children[index[i]];
369
370 if (data == 0) { GUM_ERROR(NotFound, "the datum could not be found") }
371
372 return *(current_node->data);
373 }
374
375 // returns a given node of the tree
376
377 template < typename Key, typename Data >
379 IndexedTree< Key, Data >::getNode(const std::vector< Key >& index) const {
380 IndexedTree< Key, Data >* current_node = const_cast< IndexedTree< Key, Data >* >(this);
381
382 for (unsigned int i = 0; i < index.size(); ++i)
383 current_node = current_node->children[index[i]];
384
385 return *current_node;
386 }
387
388} /* namespace gum */
Safe Iterators for hashtables.
Exception : a similar element already exists.
The class for storing the nodes of the Arborescence.
Definition indexedTree.h:73
void insertNode(const std::vector< Key > &index, const Data *data)
Adds a new node into the tree.
Data * data
The data stored into the node.
~IndexedTree()
Class destructor.
void setNode(const std::vector< Key > &index, Data *data)
Updates the value of a node (or adds it if it does not already exist).
Data & getData(const std::vector< Key > &index) const
Returns the value of a given node of the tree.
HashTable< Key, IndexedTree< Key, Data > * > children
The list of children nodes of the current node.
Key key
The key of the current node.
IndexedTree< Key, Data > * parent
The parent of the node.
IndexedTree< Key, Data > & getNode(const std::vector< Key > &index) const
Returns a given node of the tree.
IndexedTree< Key, Data > & operator=(const IndexedTree< Key, Data > &from)
Copy operator.
IndexedTree(Data *data=nullptr)
Creates a tree with one node with or without data.
Exception : the element we looked for cannot be found.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
Class for storing trees (as data structures, not graphs).
gum is the global namespace for all aGrUM entities
Definition agrum.h:46