2 Copyright (c) 2002-2016 Tampere University.
4 This file is part of TTA-Based Codesign Environment (TCE).
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:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
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.
27 * Implementation of BitTrie class.
29 * Created on: 2.2.2016
30 * @author Henry Linjamäki 2016 (henry.linjamaki-no.spam-tut.fi)
39#include "MathTools.hh"
40#include "Conversion.hh"
43 * Constructs an empty bit trie where patterns to be stored are read starting
46template<class DataType, class ValueType>
48BitTrie<DataType, ValueType>::BitTrie() {
53 * Constructs an empty bit trie where patterns to be stored are read in order
56 * @param bitReadLeftToRight If true, patterns are read MSB first. Otherwise,
57 * they are read LSB first.
59template<class DataType, class ValueType>
61BitTrie<DataType, ValueType>::BitTrie(bool bitReadLeftToRight)
62 : bitReadLeftToRight_(bitReadLeftToRight) {
67 * Private constructor.
69template<class DataType, class ValueType>
71BitTrie<DataType, ValueType>::BitTrie(
72 bool bitReadLeftToRight,
74 : bitReadLeftToRight_(bitReadLeftToRight), parent_(&parent) {
83template<class DataType, class ValueType>
85BitTrie<DataType, ValueType>::~BitTrie() {
86 for (auto& node : node_) {
96 * Returns count where the given pattern overlaps with the patterns stored.
98 * @param bits The pattern.
101template<class DataType, class ValueType>
104BitTrie<DataType, ValueType>::frequency(
105 const BitTrie<DataType, ValueType>::BitVector& bits) const {
107 if (width(bits) == 0) {
110 BitTrie* nextNode = node_[nextBit(bits)];
112 return nextNode->frequency(stripBit(bits));
120 * Return true if the trie has the exact bit pattern.
122template<class DataType, class ValueType>
125BitTrie<DataType, ValueType>::check(
126 const BitTrie<DataType, ValueType>::BitVector& bits) const {
128 const BitTrie* found = findNode(bits);
130 if (found == nullptr) {
133 if (isRootNode(*found)) {
137 return nodeTerminatesPattern(*found);
142 * Inserts new pattern into the trie with default constructed data.
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.
148template<class DataType, class ValueType>
151BitTrie<DataType, ValueType>::insert(
152 BitTrie<DataType, ValueType>::BitVector bits) {
154 return insert(bits, DataType());
159 * Inserts new pattern into the trie and attaches the given data to it.
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.
165template<class DataType, class ValueType>
168BitTrie<DataType, ValueType>::insert(
169 BitTrie<DataType, ValueType>::BitVector bits,
170 const DataType& data) {
172 if (isRootNode(*this) && check(bits)) {
175 if (width(bits) == 0 && isRootNode(*this)) {
179 if (width(bits) == 0) {
181 assert(nodeTerminatesPattern(*this));
182 if (data_ == nullptr) {
183 data_ = new DataType(data);
190 BitTrie*& node = node_[nextBit(bits)];
191 if (node == nullptr) {
192 node = new BitTrie(bitReadLeftToRight_, *this);
194 assert(node_[nextBit(bits)] != nullptr);
195 assert(node_[nextBit(bits)]->parent_ == this);
196 assert(node_[nextBit(bits)] != this);
198 return node->insert(stripBit(bits), data);
203 * Erases the given exact pattern from the trie.
205 * Data associated to the pattern is deleted.
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).
211template<class DataType, class ValueType>
214BitTrie<DataType, ValueType>::erase(
215 BitTrie<DataType, ValueType>::BitVector bits) {
217 if (parent_ == nullptr && !check(bits)) {
221 if (width(bits) == 0) {
222 if (parent_ == nullptr) {
225 if (frequency_) frequency_--;
229 BitTrie*& node = node_[nextBit(bits)];
231 if (node->erase(stripBit(bits))) {
233 if (node->frequency_ == 0) {
246 * Returns shortest unambiguous pattern in the trie.
248 * In a case where there is multiple patterns of same length, the smallest in
249 * the binary value is returned.
251template<class DataType, class ValueType>
253typename BitTrie<DataType, ValueType>::BitVector
254BitTrie<DataType, ValueType>::uniqueUnusedPrefix() const {
256 return uniqueUnusedPrefixImpl(*this);
261 * Returns data associated with the bit pattern.
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).
267template <class DataType, class ValueType>
269BitTrie<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)) + ".");
275 if (found->data_ == nullptr) {
276 found->data_ = new DataType();
278 return *found->data_;
283 * Returns width of the BitVector as reference.
285template<class DataType, class ValueType>
287typename BitTrie<DataType, ValueType>::WidthType&
288BitTrie<DataType, ValueType>::width(
289 BitVector& bitVector) {
291 return std::get<1>(bitVector);
296 * Returns width of the BitVector as constant reference.
298template<class DataType, class ValueType>
300const typename BitTrie<DataType, ValueType>::WidthType&
301BitTrie<DataType, ValueType>::width(
302 const BitVector& bitVector) {
304 return std::get<1>(bitVector);
309 * Returns value of the BitVector as reference.
311template<class DataType, class ValueType>
314BitTrie<DataType, ValueType>::value(
315 BitVector& bitVector) {
317 return std::get<0>(bitVector);
322 * Returns value of the BitVector as constant reference.
324template<class DataType, class ValueType>
327BitTrie<DataType, ValueType>::value(
328 const BitVector& bitVector) {
330 return std::get<0>(bitVector);
335 * Returns next bit in the read order set in the trie.
337template<class DataType, class ValueType>
340BitTrie<DataType, ValueType>::nextBit(
341 const BitVector& bits) const {
343 assert(width(bits) > 0);
344 return MathTools::bit(value(bits), bitReadLeftToRight_?(width(bits)-1):0);
349 * Returns BitVector with one bit removed from it in the read order set in the
352 * The bit to removed is same that would be returned by nextBit() method.
354template<class DataType, class ValueType>
356typename BitTrie<DataType, ValueType>::BitVector
357BitTrie<DataType, ValueType>::stripBit(BitVector bits) const {
359 assert(width(bits) > 0);
361 if (!bitReadLeftToRight_) {
362 value(bits) = value(bits) >> 1;
369 * Looks for trie node by the pattern.
371 * @param bits The Pattern.
372 * @return Returns pointer to the found node. If not found, return nullptr.
374template<class DataType, class ValueType>
376BitTrie<DataType, ValueType>*
377BitTrie<DataType, ValueType>::findNode(const BitVector& bits) {
378 if (width(bits) == 0) {
382 BitTrie* nextNode = node_[nextBit(bits)];
383 if (nextNode == nullptr) {
386 return nextNode->findNode(stripBit(bits));
392 * Const version of findNode() method.
394template<class DataType, class ValueType>
396const BitTrie<DataType, ValueType>*
397BitTrie<DataType, ValueType>::findNode(const BitVector& bits) const {
398 if (width(bits) == 0) {
402 const BitTrie* nextNode = node_[nextBit(bits)];
403 if (nextNode == nullptr) {
406 return nextNode->findNode(stripBit(bits));
412 * The implementation of uniqueUnusedPrefix() method.
414template<class DataType, class ValueType>
416typename BitTrie<DataType, ValueType>::BitVector
417BitTrie<DataType, ValueType>::uniqueUnusedPrefixImpl(const BitTrie& bitTrie) {
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();
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]);
432 queue.clear(); // break from while clause
439 value(result) = availableBit;
441 assert(current != nullptr);
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));
450 value(result) = MathTools::concatenateBits(
451 value(result), width(result), i, 1);
457 current = current->parent_;
465 * Clears all patterns stored to the trie and deletes any data associated to
468template<class DataType, class ValueType>
471BitTrie<DataType, ValueType>::clear() {
472 for (int i = 0; i < 2; i++) {
484 * Returns the count of stored patterns.
486template<class DataType, class ValueType>
489BitTrie<DataType, ValueType>::size() const {
490 assert(parent_ == nullptr && "size(): Valid call only for root node.");
496 * Returns longest pattern in the trie that as whole acts as prefix to the
499template<class DataType, class ValueType>
501typename BitTrie<DataType, ValueType>::BitVector
502BitTrie<DataType, ValueType>::longestCompletePattern(
503 const BitVector& bits) const {
505 // Traverse bit trie until bits or nodes are run out. //
506 if (width(bits) > 0) {
507 const BitTrie* nextNode = node_[nextBit(bits)];
509 return nextNode->longestCompletePattern(stripBit(bits));
513 // Traverse towards root to find a node that terminates a bit pattern. //
514 const BitTrie* node = this;
516 if (nodeTerminatesPattern(*node)) {
517 // Found complete pattern.
518 return patternAtNode(*node);
520 } while((node = node->parent_));
522 // No pattern found. //
523 return BitVector{0, 0};
530template<class DataType, class ValueType>
533BitTrie<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);
544 * Returns true id some bit pattern is terminated at the node.
546template<class DataType, class ValueType>
549BitTrie<DataType, ValueType>::nodeTerminatesPattern(const BitTrie& node) {
550 WidthType subFreq = 0;
551 for (const BitTrie* subTrie : node.node_) {
552 subFreq += subTrie?subTrie->frequency_:0;
554 assert(node.frequency_ >= subFreq);
555 assert((node.frequency_ - subFreq) < 2);
556 if ((node.frequency_ - subFreq) == 1) {
565 * Returns the BitVector that the node describes.
567template<class DataType, class ValueType>
569typename BitTrie<DataType, ValueType>::BitVector
570BitTrie<DataType, ValueType>::patternAtNode(const BitTrie& node) {
571 if (isRootNode(node)) {
572 return BitVector{0, 0};
574 BitVector result{0, depth(node)};
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));
582 value(result), width(result)-1-i, nodeBitValue(*currentNode));
584 currentNode = currentNode->parent_;
591 * Returns the bit value of the node.
594template<class DataType, class ValueType>
597BitTrie<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);
607 * Returns true if the node is root node of the trie. Otherwise returns false.
609template<class DataType, class ValueType>
612BitTrie<DataType, ValueType>::isRootNode(const BitTrie& node) {
613 return (node.parent_ == nullptr);
618 * Returns the depth of the node and also number of bits it describes.
620template<class DataType, class ValueType>
623BitTrie<DataType, ValueType>::depth(const BitTrie& node) {
625 const BitTrie* parent = node.parent_;
628 parent = parent->parent_;