aGrUM 3.1.1
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-2026 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-2026 *
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
41#pragma once
42
43
50
51// to ease IDE parser
53
54namespace gum {
55 /* =========================================================================*/
56 /* =========================================================================*/
57 /* === IMPLEMENTATION OF NODES FOR GENERIC TREE (DATA) STRUCTURE === */
58 /* =========================================================================*/
59 /* =========================================================================*/
60
61 // creates a tree with one node (with or without data)
62
63 template < typename Key, typename Data >
64 IndexedTree< Key, Data >::IndexedTree(const Key& theKey, Data* theData) :
65 key(theKey), data(theData), parent(0) {
66 // for debugging purposes
67 GUM_CONSTRUCTOR(IndexedTree);
68 }
69
70 // creates a tree with one node (with or without data)
71
72 template < typename Key, typename Data >
73 IndexedTree< Key, Data >::IndexedTree(Data* theData) : data(theData), parent(0) {
74 // for debugging purposes
75 GUM_CONSTRUCTOR(IndexedTree);
76 }
77
78 // creates a tree with one node with data
79
80 template < typename Key, typename Data >
81 IndexedTree< Key, Data >::IndexedTree(const Key& theKey, const Data& theData) :
82 key(theKey), data(new Data(theData)), parent(0) {
83 // for debugging purposes
84 GUM_CONSTRUCTOR(IndexedTree);
85 }
86
87 // copy constructor
88
89 template < typename Key, typename Data >
91 key(from.key), data(0), parent(0) {
92 // for debugging purposes
93 GUM_CONS_CPY(IndexedTree);
94
95 try {
96 // create the data of the node
97 if (from.data) data = new Data(*from.data);
98
99 // create and link properly the children
100 children = from.children;
101
102 for (HashTableIteratorSafe< Key, IndexedTree< Key, Data > > iter = children.begin();
103 iter != children.end();
104 ++iter)
105 iter->parent = this;
106 } catch (...) {
107 if (data) delete data;
108
109 children.clear();
110
111 throw;
112 }
113 }
114
115 // copy operator
116
117 template < typename Key, typename Data >
120 // avoid self assignment
121 if (this != &from) {
122 // for debugging purposes
123 GUM_OP_CPY(IndexedTree);
124
125 try {
126 key = from.key;
127
128 if (data) delete data;
129
130 if (from.data) data = new Data(*from.data);
131 else data = 0;
132
133 children = from.children;
134
135 for (HashTableIteratorSafe< Key, IndexedTree< Key, Data > > iter = children.begin();
136 iter != children.end();
137 ++iter)
138 iter->parent = this;
139 } catch (...) {
140 if (data) delete data;
141
142 children.clear();
143
144 throw;
145 }
146 }
147
148 return *this;
149 }
150
151 // destructor
152
153 template < typename Key, typename Data >
155 // for debugging purposes
156 GUM_DESTRUCTOR(IndexedTree);
157
158 if (data) delete data;
159 }
160
161 // adds a new node into the tree
162
163 template < typename Key, typename Data >
164 void IndexedTree< Key, Data >::insertNode(const std::vector< Key >& index, const Data* theData) {
165 // parse the tree until we are on the proper index. Then, insert the new
166 // node.
167 // current_node is a pointer on the node of the tree corresponding to
168 // position
169 // i in vector index. When i+2 < index.size(), we need go down into the tree
170 // structure before we can insert the new node
171 IndexedTree< Key, Data >* current_node = this;
172 unsigned int i;
173
174 for (i = 0; i + 1 < index.size(); ++i) {
175 // if the node that should be on the path between the root of the tree and
176 // the node that we wish to insert does not exist, create it
177 if (!children.exists(index[i])) {
178 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
179 current_node->children.insert(index[i], new_node);
180 new_node->parent = this;
181 current_node = new_node;
182 } else current_node = current_node->children[index[i]];
183 }
184
185 // here, we can insert the new node. if ind + 1 == index.size(), this means
186 // that
187 // the index vector was not empty, else the vector was empty and we are at
188 // the
189 // root of the tree
190 if (i + 1 == index.size()) {
191 // if the node to be inserted already exist, throw an exception
192 if (current_node->children.exists(index[i])) {
193 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
194 }
195
196 // here, the node to be inserted does not exist, so we must create it
198 = new IndexedTree< Key, Data >(index[i], const_cast< Data* >(theData));
199
200 current_node->children.insert(index[i], new_node);
201
202 new_node->parent = current_node;
203 } else {
204 // here, the node to be inserted is the root of the tree (so it already
205 // exists)
206 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
207 }
208 }
209
210 // adds a new node into the tree
211
212 template < typename Key, typename Data >
213 void IndexedTree< Key, Data >::insertNode(const std::vector< Key >& index, const Data& theData) {
214 // parse the tree until we are on the proper index. Then, insert the new
215 // node.
216 // current_node is a pointer on the node of the tree corresponding to
217 // position
218 // i in vector index. When i+2 < index.size(), we need go down into the tree
219 // structure before we can insert the new node
220 IndexedTree< Key, Data >* current_node = this;
221 unsigned int i;
222
223 for (i = 0; i + 1 < index.size(); ++i) {
224 // if the node that should be on the path between the root of the tree and
225 // the node that we wish to insert does not exist, create it
226 if (!children.exists(index[i])) {
227 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
228 current_node->children.insert(index[i], new_node);
229 new_node->parent = this;
230 current_node = new_node;
231 } else current_node = current_node->children[index[i]];
232 }
233
234 // here, we can insert the new node. if ind + 1 == index.size(), this means
235 // that
236 // the index vector was not empty, else the vector was empty and we are at
237 // the
238 // root of the tree
239 if (i + 1 == index.size()) {
240 // if the node to be inserted already exist, throw an exception
241 if (current_node->children.exists(index[i])) {
242 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
243 }
244
245 // here, the node to be inserted does not exist, so we must create it
246 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
247
248 current_node->children.insert(index[i], new_node);
249
250 new_node->parent = current_node;
251 } else {
252 // here, the node to be inserted is the root of the tree (so it already
253 // exists)
254 GUM_ERROR(DuplicateElement, "the indexed tree already contains the node")
255 }
256 }
257
258 // updates the value of a node (or adds it if it does not already exist)
259
260 template < typename Key, typename Data >
261 void IndexedTree< Key, Data >::setNode(const std::vector< Key >& index, Data* theData) {
262 // parse the tree until we are on the proper index. Then, insert the new
263 // node.
264 // current_node is a pointer on the node of the tree corresponding to
265 // position
266 // i in vector index. When i+2 < index.size(), we need go down into the tree
267 // structure before we can insert the new node
268 IndexedTree< Key, Data >* current_node = this;
269 unsigned int i;
270
271 for (i = 0; i + 1 < index.size(); ++i) {
272 // if the node that should be on the path between the root of the tree and
273 // the node that we wish to insert does not exist, create it
274 if (!children.exists(index[i])) {
275 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
276 current_node->children.insert(index[i], new_node);
277 new_node->parent = this;
278 current_node = new_node;
279 } else current_node = current_node->children[index[i]];
280 }
281
282 // here, we can set the new node. if ind + 1 == index.size(), this means
283 // that
284 // the index vector was not empty, else the vector was empty and we are at
285 // the
286 // root of the tree
287 if (i + 1 == index.size()) {
288 // if the node to be set does not exist, create it, else modify it
289 if (current_node->children.exists(index[i])) {
290 IndexedTree< Key, Data >* node = current_node->children[index[i]];
291
292 if (node->data) delete node->data;
293
294 node->data = theData;
295 } else {
296 // here, the node tobe set does not exist, so we must create it
297 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
298 current_node->children.insert(index[i], new_node);
299 new_node->parent = current_node;
300 }
301 } else {
302 // here, the node to be set is the root of the tree (so it does already
303 // exist
304 if (data) delete data;
305
306 data = theData;
307 }
308 }
309
310 // updates the value of a node (or adds it if it does not already exist)
311
312 template < typename Key, typename Data >
313 void IndexedTree< Key, Data >::setNode(const std::vector< Key >& index, const Data& theData) {
314 // parse the tree until we are on the proper index. Then, insert the new
315 // node.
316 // current_node is a pointer on the node of the tree corresponding to
317 // position
318 // i in vector index. When i+2 < index.size(), we need go down into the tree
319 // structure before we can insert the new node
320 IndexedTree< Key, Data >* current_node = this;
321 unsigned int i;
322
323 for (i = 0; i + 1 < index.size(); ++i) {
324 // if the node that should be on the path between the root of the tree and
325 // the node that we wish to insert does not exist, create it
326 if (!children.exists(index[i])) {
327 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], (Data*)0);
328 current_node->children.insert(index[i], new_node);
329 new_node->parent = this;
330 current_node = new_node;
331 } else current_node = current_node->children[index[i]];
332 }
333
334 // here, we can set the new node. if ind + 1 == index.size(), this means
335 // that
336 // the index vector was not empty, else the vector was empty and we are at
337 // the
338 // root of the tree
339 if (i + 1 == index.size()) {
340 // if the node to be set does not exist, create it, else modify it
341 if (current_node->children.exists(index[i])) {
342 IndexedTree< Key, Data >* node = current_node->children[index[i]];
343
344 if (node->data) delete node->data;
345
346 node->data = new Data(theData);
347 } else {
348 // here, the node tobe set does not exist, so we must create it
349 IndexedTree< Key, Data >* new_node = new IndexedTree< Key, Data >(index[i], theData);
350 current_node->children.insert(index[i], new_node);
351 new_node->parent = current_node;
352 }
353 } else {
354 // here, the node to be set is the root of the tree (so it does already
355 // exist
356 if (data) delete data;
357
358 data = new Data(theData);
359 }
360 }
361
362 // returns the value of a given test from the cache
363
364 template < typename Key, typename Data >
365 Data& IndexedTree< Key, Data >::getData(const std::vector< Key >& index) const {
366 IndexedTree< Key, Data >* current_node = const_cast< IndexedTree< Key, Data >* >(this);
367
368 for (unsigned int i = 0; i < index.size(); ++i)
369 current_node = current_node->children[index[i]];
370
371 if (data == 0) { GUM_ERROR(NotFound, "the datum could not be found") }
372
373 return *(current_node->data);
374 }
375
376 // returns a given node of the tree
377
378 template < typename Key, typename Data >
380 IndexedTree< Key, Data >::getNode(const std::vector< Key >& index) const {
381 IndexedTree< Key, Data >* current_node = const_cast< IndexedTree< Key, Data >* >(this);
382
383 for (unsigned int i = 0; i < index.size(); ++i)
384 current_node = current_node->children[index[i]];
385
386 return *current_node;
387 }
388
389} /* 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.
IndexedTree< Key, Data > & getNode(const std::vector< Key > &index) const
Returns a given node of the tree.
void setNode(const std::vector< Key > &index, Data *data)
Updates the value of a node (or adds it if it does not already exist).
HashTable< Key, IndexedTree< Key, Data > * > children
The list of children nodes of the current node.
Key key
The key of the current node.
Data & getData(const std::vector< Key > &index) const
Returns the value of a given node of the tree.
IndexedTree< Key, Data > * parent
The parent of the node.
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:76
Class for storing trees (as data structures, not graphs).
gum is the global namespace for all aGrUM entities
Definition agrum.h:46