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
46 template<class DataType, class ValueType>
48 BitTrie<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.
59 template<class DataType, class ValueType>
61 BitTrie<DataType, ValueType>::BitTrie(bool bitReadLeftToRight)
62 : bitReadLeftToRight_(bitReadLeftToRight) {
67 * Private constructor.
69 template<class DataType, class ValueType>
71 BitTrie<DataType, ValueType>::BitTrie(
72 bool bitReadLeftToRight,
74 : bitReadLeftToRight_(bitReadLeftToRight), parent_(&parent) {
83 template<class DataType, class ValueType>
85 BitTrie<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.
101 template<class DataType, class ValueType>
104 BitTrie<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.
122 template<class DataType, class ValueType>
125 BitTrie<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.
148 template<class DataType, class ValueType>
151 BitTrie<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.
165 template<class DataType, class ValueType>
168 BitTrie<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).
211 template<class DataType, class ValueType>
214 BitTrie<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.
251 template<class DataType, class ValueType>
253 typename BitTrie<DataType, ValueType>::BitVector
254 BitTrie<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).
267 template <class DataType, class ValueType>
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)) + ".");
275 if (found->data_ == nullptr) {
276 found->data_ = new DataType();
278 return *found->data_;
283 * Returns width of the BitVector as reference.
285 template<class DataType, class ValueType>
287 typename BitTrie<DataType, ValueType>::WidthType&
288 BitTrie<DataType, ValueType>::width(
289 BitVector& bitVector) {
291 return std::get<1>(bitVector);
296 * Returns width of the BitVector as constant reference.
298 template<class DataType, class ValueType>
300 const typename BitTrie<DataType, ValueType>::WidthType&
301 BitTrie<DataType, ValueType>::width(
302 const BitVector& bitVector) {
304 return std::get<1>(bitVector);
309 * Returns value of the BitVector as reference.
311 template<class DataType, class ValueType>
314 BitTrie<DataType, ValueType>::value(
315 BitVector& bitVector) {
317 return std::get<0>(bitVector);
322 * Returns value of the BitVector as constant reference.
324 template<class DataType, class ValueType>
327 BitTrie<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.
337 template<class DataType, class ValueType>
340 BitTrie<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.
354 template<class DataType, class ValueType>
356 typename BitTrie<DataType, ValueType>::BitVector
357 BitTrie<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.
374 template<class DataType, class ValueType>
376 BitTrie<DataType, ValueType>*
377 BitTrie<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.
394 template<class DataType, class ValueType>
396 const BitTrie<DataType, ValueType>*
397 BitTrie<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.
414 template<class DataType, class ValueType>
416 typename BitTrie<DataType, ValueType>::BitVector
417 BitTrie<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
468 template<class DataType, class ValueType>
471 BitTrie<DataType, ValueType>::clear() {
472 for (int i = 0; i < 2; i++) {
484 * Returns the count of stored patterns.
486 template<class DataType, class ValueType>
489 BitTrie<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
499 template<class DataType, class ValueType>
501 typename BitTrie<DataType, ValueType>::BitVector
502 BitTrie<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};
530 template<class DataType, class ValueType>
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);
544 * Returns true id some bit pattern is terminated at the node.
546 template<class DataType, class ValueType>
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;
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.
567 template<class DataType, class ValueType>
569 typename BitTrie<DataType, ValueType>::BitVector
570 BitTrie<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.
594 template<class DataType, class ValueType>
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);
607 * Returns true if the node is root node of the trie. Otherwise returns false.
609 template<class DataType, class ValueType>
612 BitTrie<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.
620 template<class DataType, class ValueType>
623 BitTrie<DataType, ValueType>::depth(const BitTrie& node) {
625 const BitTrie* parent = node.parent_;
628 parent = parent->parent_;