OpenASIP  2.0
BitTrie.icc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2002-2016 Tampere University.
3 
4  This file is part of TTA-Based Codesign Environment (TCE).
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  */
24 /*
25  * @file BitTrie.icc
26  *
27  * Implementation of BitTrie class.
28  *
29  * Created on: 2.2.2016
30  * @author Henry Linjamäki 2016 (henry.linjamaki-no.spam-tut.fi)
31  * @note rating: red
32  */
33 
34 #include "BitTrie.hh"
35 
36 #include <cassert>
37 #include <list>
38 
39 #include "MathTools.hh"
40 #include "Conversion.hh"
41 
42 /**
43  * Constructs an empty bit trie where patterns to be stored are read starting
44  * from LSB.
45  */
46 template<class DataType, class ValueType>
47 inline
48 BitTrie<DataType, ValueType>::BitTrie() {
49 }
50 
51 
52 /**
53  * Constructs an empty bit trie where patterns to be stored are read in order
54  * of choice.
55  *
56  * @param bitReadLeftToRight If true, patterns are read MSB first. Otherwise,
57  * they are read LSB first.
58  */
59 template<class DataType, class ValueType>
60 inline
61 BitTrie<DataType, ValueType>::BitTrie(bool bitReadLeftToRight)
62  : bitReadLeftToRight_(bitReadLeftToRight) {
63 }
64 
65 
66 /**
67  * Private constructor.
68  */
69 template<class DataType, class ValueType>
70 inline
71 BitTrie<DataType, ValueType>::BitTrie(
72  bool bitReadLeftToRight,
73  BitTrie& parent)
74  : bitReadLeftToRight_(bitReadLeftToRight), parent_(&parent) {
75 
76 
77 }
78 
79 
80 /**
81  * Desctructor.
82  */
83 template<class DataType, class ValueType>
84 inline
85 BitTrie<DataType, ValueType>::~BitTrie() {
86  for (auto& node : node_) {
87  delete node;
88  node = nullptr;
89  }
90  delete data_;
91  data_ = nullptr;
92 }
93 
94 
95 /**
96  * Returns count where the given pattern overlaps with the patterns stored.
97  *
98  * @param bits The pattern.
99  * @return The count.
100  */
101 template<class DataType, class ValueType>
102 inline
103 unsigned
104 BitTrie<DataType, ValueType>::frequency(
105  const BitTrie<DataType, ValueType>::BitVector& bits) const {
106 
107  if (width(bits) == 0) {
108  return frequency_;
109  }
110  BitTrie* nextNode = node_[nextBit(bits)];
111  if (nextNode) {
112  return nextNode->frequency(stripBit(bits));
113  } else {
114  return 0;
115  }
116 }
117 
118 
119 /**
120  * Return true if the trie has the exact bit pattern.
121  */
122 template<class DataType, class ValueType>
123 inline
124 bool
125 BitTrie<DataType, ValueType>::check(
126  const BitTrie<DataType, ValueType>::BitVector& bits) const {
127 
128  const BitTrie* found = findNode(bits);
129 
130  if (found == nullptr) {
131  return false;
132  }
133  if (isRootNode(*found)) {
134  return false;
135  }
136 
137  return nodeTerminatesPattern(*found);
138 }
139 
140 
141 /**
142  * Inserts new pattern into the trie with default constructed data.
143  *
144  * @param bits The bit pattern to add
145  * @return True, if the pattern is added to the trie. Otherwise, returns false
146  * and the pattern pattern is not added.
147  */
148 template<class DataType, class ValueType>
149 inline
150 bool
151 BitTrie<DataType, ValueType>::insert(
152  BitTrie<DataType, ValueType>::BitVector bits) {
153 
154  return insert(bits, DataType());
155 }
156 
157 
158 /**
159  * Inserts new pattern into the trie and attaches the given data to it.
160  *
161  * @param bits The bit pattern to add
162  * @return True, if the pattern is added to the trie. Otherwise, returns false
163  * and the pattern pattern is not added.
164  */
165 template<class DataType, class ValueType>
166 inline
167 bool
168 BitTrie<DataType, ValueType>::insert(
169  BitTrie<DataType, ValueType>::BitVector bits,
170  const DataType& data) {
171 
172  if (isRootNode(*this) && check(bits)) {
173  return false;
174  }
175  if (width(bits) == 0 && isRootNode(*this)) {
176  return false;
177  }
178 
179  if (width(bits) == 0) {
180  frequency_++;
181  assert(nodeTerminatesPattern(*this));
182  if (data_ == nullptr) {
183  data_ = new DataType(data);
184  } else {
185  *data_ = data;
186  }
187  return true;
188  }
189 
190  BitTrie*& node = node_[nextBit(bits)];
191  if (node == nullptr) {
192  node = new BitTrie(bitReadLeftToRight_, *this);
193  }
194  assert(node_[nextBit(bits)] != nullptr);
195  assert(node_[nextBit(bits)]->parent_ == this);
196  assert(node_[nextBit(bits)] != this);
197  frequency_++;
198  return node->insert(stripBit(bits), data);
199 }
200 
201 
202 /**
203  * Erases the given exact pattern from the trie.
204  *
205  * Data associated to the pattern is deleted.
206  *
207  * @return Returns true if the given pattern was erased from the trie.
208  * Otherwise, returns false (i.e. trie does not have the pattern).
209  *
210  */
211 template<class DataType, class ValueType>
212 inline
213 bool
214 BitTrie<DataType, ValueType>::erase(
215  BitTrie<DataType, ValueType>::BitVector bits) {
216 
217  if (parent_ == nullptr && !check(bits)) {
218  return false;
219  }
220 
221  if (width(bits) == 0) {
222  if (parent_ == nullptr) {
223  return false;
224  }
225  if (frequency_) frequency_--;
226  return true;
227  }
228 
229  BitTrie*& node = node_[nextBit(bits)];
230  if (node) {
231  if (node->erase(stripBit(bits))) {
232  frequency_--;
233  if (node->frequency_ == 0) {
234  delete node;
235  node = nullptr;
236  }
237  }
238  return true;
239  } else {
240  return false;
241  }
242 }
243 
244 
245 /**
246  * Returns shortest unambiguous pattern in the trie.
247  *
248  * In a case where there is multiple patterns of same length, the smallest in
249  * the binary value is returned.
250  */
251 template<class DataType, class ValueType>
252 inline
253 typename BitTrie<DataType, ValueType>::BitVector
254 BitTrie<DataType, ValueType>::uniqueUnusedPrefix() const {
255 
256  return uniqueUnusedPrefixImpl(*this);
257 }
258 
259 
260 /**
261  * Returns data associated with the bit pattern.
262  *
263  * @param bits The pattern as key to the data
264  * @return The data stored with one of the insert() methods.
265  * @exception KeyNotFound If the trie does not have the given pattern (bits).
266  */
267 template <class DataType, class ValueType>
268 inline DataType&
269 BitTrie<DataType, ValueType>::at(BitTrie<DataType, ValueType>::BitVector bits) {
270  BitTrie* found = findNode(bits);
271  if (found == nullptr) {
272  THROW_EXCEPTION(KeyNotFound, "BitTrie does not have pattern of 0b"
273  + Conversion::toBinary(value(bits), width(bits)) + ".");
274  } else {
275  if (found->data_ == nullptr) {
276  found->data_ = new DataType();
277  }
278  return *found->data_;
279  }
280 }
281 
282 /**
283  * Returns width of the BitVector as reference.
284  */
285 template<class DataType, class ValueType>
286 inline
287 typename BitTrie<DataType, ValueType>::WidthType&
288 BitTrie<DataType, ValueType>::width(
289  BitVector& bitVector) {
290 
291  return std::get<1>(bitVector);
292 }
293 
294 
295 /**
296  * Returns width of the BitVector as constant reference.
297  */
298 template<class DataType, class ValueType>
299 inline
300 const typename BitTrie<DataType, ValueType>::WidthType&
301 BitTrie<DataType, ValueType>::width(
302  const BitVector& bitVector) {
303 
304  return std::get<1>(bitVector);
305 }
306 
307 
308 /**
309  * Returns value of the BitVector as reference.
310  */
311 template<class DataType, class ValueType>
312 inline
313 ValueType&
314 BitTrie<DataType, ValueType>::value(
315  BitVector& bitVector) {
316 
317  return std::get<0>(bitVector);
318 }
319 
320 
321 /**
322  * Returns value of the BitVector as constant reference.
323  */
324 template<class DataType, class ValueType>
325 inline
326 const ValueType&
327 BitTrie<DataType, ValueType>::value(
328  const BitVector& bitVector) {
329 
330  return std::get<0>(bitVector);
331 }
332 
333 
334 /**
335  * Returns next bit in the read order set in the trie.
336  */
337 template<class DataType, class ValueType>
338 inline
339 bool
340 BitTrie<DataType, ValueType>::nextBit(
341  const BitVector& bits) const {
342 
343  assert(width(bits) > 0);
344  return MathTools::bit(value(bits), bitReadLeftToRight_?(width(bits)-1):0);
345 }
346 
347 
348 /**
349  * Returns BitVector with one bit removed from it in the read order set in the
350  * trie.
351  *
352  * The bit to removed is same that would be returned by nextBit() method.
353  */
354 template<class DataType, class ValueType>
355 inline
356 typename BitTrie<DataType, ValueType>::BitVector
357 BitTrie<DataType, ValueType>::stripBit(BitVector bits) const {
358 
359  assert(width(bits) > 0);
360  width(bits)--;
361  if (!bitReadLeftToRight_) {
362  value(bits) = value(bits) >> 1;
363  }
364  return bits;
365 }
366 
367 
368 /**
369  * Looks for trie node by the pattern.
370  *
371  * @param bits The Pattern.
372  * @return Returns pointer to the found node. If not found, return nullptr.
373  */
374 template<class DataType, class ValueType>
375 inline
376 BitTrie<DataType, ValueType>*
377 BitTrie<DataType, ValueType>::findNode(const BitVector& bits) {
378  if (width(bits) == 0) {
379  return this;
380  }
381 
382  BitTrie* nextNode = node_[nextBit(bits)];
383  if (nextNode == nullptr) {
384  return nullptr;
385  } else {
386  return nextNode->findNode(stripBit(bits));
387  }
388 }
389 
390 
391 /**
392  * Const version of findNode() method.
393  */
394 template<class DataType, class ValueType>
395 inline
396 const BitTrie<DataType, ValueType>*
397 BitTrie<DataType, ValueType>::findNode(const BitVector& bits) const {
398  if (width(bits) == 0) {
399  return this;
400  }
401 
402  const BitTrie* nextNode = node_[nextBit(bits)];
403  if (nextNode == nullptr) {
404  return nullptr;
405  } else {
406  return nextNode->findNode(stripBit(bits));
407  }
408 }
409 
410 
411 /**
412  * The implementation of uniqueUnusedPrefix() method.
413  */
414 template<class DataType, class ValueType>
415 inline
416 typename BitTrie<DataType, ValueType>::BitVector
417 BitTrie<DataType, ValueType>::uniqueUnusedPrefixImpl(const BitTrie& bitTrie) {
418 
419  std::list<const BitTrie*> queue;
420  queue.push_back(&bitTrie);
421  const BitTrie* current = nullptr;
422  bool availableBit = false;
423  while(!queue.empty()) {
424  current = queue.front();
425  queue.pop_front();
426  for (unsigned i = 0; i < 2; i++) {
427  if (current->node_[i]) {
428  assert(current->node_[i]->parent_ == current);
429  queue.push_back(current->node_[i]);
430  } else {
431  availableBit = i;
432  queue.clear(); // break from while clause
433  break;
434  }
435  }
436  }
437 
438  BitVector result;
439  value(result) = availableBit;
440  width(result) = 1;
441  assert(current != nullptr);
442 
443  while (current->parent_ != nullptr) {
444  for (unsigned i = 0; i < 2; i++) {
445  if (current->parent_->node_[i] == current) {
446  if (current->bitReadLeftToRight_) {
447  value(result) = MathTools::concatenateBits(
448  i, 1, value(result), width(result));
449  } else {
450  value(result) = MathTools::concatenateBits(
451  value(result), width(result), i, 1);
452  }
453  width(result)++;
454  break;
455  }
456  }
457  current = current->parent_;
458  }
459 
460  return result;
461 }
462 
463 
464 /**
465  * Clears all patterns stored to the trie and deletes any data associated to
466  * them.
467  */
468 template<class DataType, class ValueType>
469 inline
470 void
471 BitTrie<DataType, ValueType>::clear() {
472  for (int i = 0; i < 2; i++) {
473  if (node_[i]) {
474  node_[i]->clear();
475  delete node_[i];
476  node_[i] = nullptr;
477  }
478  }
479  frequency_ = 0;
480 }
481 
482 
483 /**
484  * Returns the count of stored patterns.
485  */
486 template<class DataType, class ValueType>
487 inline
488 unsigned
489 BitTrie<DataType, ValueType>::size() const {
490  assert(parent_ == nullptr && "size(): Valid call only for root node.");
491  return frequency_;
492 }
493 
494 
495 /**
496  * Returns longest pattern in the trie that as whole acts as prefix to the
497  * given pattern.
498  */
499 template<class DataType, class ValueType>
500 inline
501 typename BitTrie<DataType, ValueType>::BitVector
502 BitTrie<DataType, ValueType>::longestCompletePattern(
503  const BitVector& bits) const {
504 
505  // Traverse bit trie until bits or nodes are run out. //
506  if (width(bits) > 0) {
507  const BitTrie* nextNode = node_[nextBit(bits)];
508  if (nextNode) {
509  return nextNode->longestCompletePattern(stripBit(bits));
510  }
511  }
512 
513  // Traverse towards root to find a node that terminates a bit pattern. //
514  const BitTrie* node = this;
515  do {
516  if (nodeTerminatesPattern(*node)) {
517  // Found complete pattern.
518  return patternAtNode(*node);
519  }
520  } while((node = node->parent_));
521 
522  // No pattern found. //
523  return BitVector{0, 0};
524 }
525 
526 
527 /**
528  * Debug method.
529  */
530 template<class DataType, class ValueType>
531 inline
532 void
533 BitTrie<DataType, ValueType>::dump(std::ostream& out) const {
534  out << this << ", " << depth(*this) << ", "
535  << value(patternAtNode(*this)) << ", "
536  << width(patternAtNode(*this)) << ", "
537  << frequency_ << std::endl;
538  if (node_[0]) node_[0]->dump(out);
539  if (node_[1]) node_[1]->dump(out);
540 }
541 
542 
543 /**
544  * Returns true id some bit pattern is terminated at the node.
545  */
546 template<class DataType, class ValueType>
547 inline
548 bool
549 BitTrie<DataType, ValueType>::nodeTerminatesPattern(const BitTrie& node) {
550  WidthType subFreq = 0;
551  for (const BitTrie* subTrie : node.node_) {
552  subFreq += subTrie?subTrie->frequency_:0;
553  }
554  assert(node.frequency_ >= subFreq);
555  assert((node.frequency_ - subFreq) < 2);
556  if ((node.frequency_ - subFreq) == 1) {
557  return true;
558  } else {
559  return false;
560  }
561 }
562 
563 
564 /**
565  * Returns the BitVector that the node describes.
566  */
567 template<class DataType, class ValueType>
568 inline
569 typename BitTrie<DataType, ValueType>::BitVector
570 BitTrie<DataType, ValueType>::patternAtNode(const BitTrie& node) {
571  if (isRootNode(node)) {
572  return BitVector{0, 0};
573  }
574  BitVector result{0, depth(node)};
575 
576  const BitTrie* currentNode = &node;
577  for (unsigned i = 0; i < width(result); i++) {
578  if (currentNode->bitReadLeftToRight_) {
579  MathTools::setBit(value(result), i, nodeBitValue(*currentNode));
580  } else {
581  MathTools::setBit(
582  value(result), width(result)-1-i, nodeBitValue(*currentNode));
583  }
584  currentNode = currentNode->parent_;
585  }
586  return result;
587 }
588 
589 
590 /**
591  * Returns the bit value of the node.
592  *
593  */
594 template<class DataType, class ValueType>
595 inline
596 bool
597 BitTrie<DataType, ValueType>::nodeBitValue(const BitTrie& node) {
598  assert(node.parent_ != nullptr
599  && "Illegal call for root node.");
600  assert((node.parent_->node_[1] == &node || node.parent_->node_[0] == &node)
601  && "Not registered to parent.");
602  return (node.parent_->node_[1] == &node);
603 }
604 
605 
606 /**
607  * Returns true if the node is root node of the trie. Otherwise returns false.
608  */
609 template<class DataType, class ValueType>
610 inline
611 bool
612 BitTrie<DataType, ValueType>::isRootNode(const BitTrie& node) {
613  return (node.parent_ == nullptr);
614 }
615 
616 
617 /**
618  * Returns the depth of the node and also number of bits it describes.
619  */
620 template<class DataType, class ValueType>
621 inline
622 unsigned
623 BitTrie<DataType, ValueType>::depth(const BitTrie& node) {
624  unsigned count = 0;
625  const BitTrie* parent = node.parent_;
626  while (parent) {
627  count++;
628  parent = parent->parent_;
629  }
630  return count;
631 }