| /* |
| * Copyright (c) 2019, 2020 Inria |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef __MEM_CACHE_COMPRESSORS_ENCODERS_HUFFMAN_HH__ |
| #define __MEM_CACHE_COMPRESSORS_ENCODERS_HUFFMAN_HH__ |
| |
| #include <cassert> |
| #include <cstdint> |
| #include <map> |
| #include <memory> |
| #include <queue> |
| #include <vector> |
| |
| #include "base/compiler.hh" |
| #include "mem/cache/compressors/encoders/base.hh" |
| |
| namespace gem5 |
| { |
| |
| GEM5_DEPRECATED_NAMESPACE(Compressor, compression); |
| namespace compression |
| { |
| GEM5_DEPRECATED_NAMESPACE(Encoder, encoder); |
| namespace encoder |
| { |
| |
| /** |
| * This encoder builds a Huffman tree using the frequency of each value to |
| * be encoded. |
| */ |
| class Huffman : public Base |
| { |
| public: |
| Huffman(uint64_t max_code_length); |
| ~Huffman() = default; |
| |
| /** |
| * Inserts the value-frequency pair in the tree. |
| * |
| * @param value The value. |
| * @param frequency The value's frequency. |
| */ |
| void sample(uint64_t value, uint64_t frequency); |
| |
| /** Generation of the code maps. This automatically builds the tree. */ |
| void generateCodeMaps(); |
| |
| Code encode(const uint64_t val) const override; |
| uint64_t decode(const uint64_t code) const override; |
| |
| private: |
| /** Node for the Huffman tree. */ |
| class Node |
| { |
| private: |
| /** Frequency of the value represented by this node. */ |
| const uint64_t _frequency; |
| |
| /** Value represented by this node, if this is a leaf node. */ |
| const uint64_t _value; |
| |
| /** The left tree. */ |
| std::unique_ptr<Node> _left; |
| |
| /** The right tree. */ |
| std::unique_ptr<Node> _right; |
| |
| public: |
| /** Initialize node as a leaf node. */ |
| Node(uint64_t value, uint64_t frequency) |
| : _frequency(frequency), _value(value), _left(), _right() |
| { |
| } |
| |
| /** Initialize node as an internal node. */ |
| Node(Node* left, Node* right) |
| : _frequency(left->getFrequency() + right->getFrequency()), |
| _value(0), _left(left), _right(right) |
| { |
| } |
| |
| /** Getter for the frequency counter. */ |
| uint64_t getFrequency() const { return _frequency; } |
| |
| /** |
| * Determine if the node is a leaf node by checking if it does not |
| * have sub-trees. |
| * |
| * @return Wether the node is a leaf node. |
| */ |
| bool |
| isLeaf() const |
| { |
| return (_left == nullptr) && (_right == nullptr); |
| } |
| |
| /** |
| * Get the leaf's value. |
| * |
| * @return The leaf's value. |
| */ |
| uint64_t |
| getValue() const |
| { |
| assert(isLeaf()); |
| return _value; |
| } |
| |
| const Node* getLeftSubTree() const { return _left.get(); } |
| const Node* getRightSubTree() const { return _right.get(); } |
| }; |
| |
| /** |
| * Maximum number of bits in a codeword. If a codeword requires more |
| * than this amount of bits, its respective value is discarded. |
| */ |
| const unsigned maxCodeLength; |
| |
| /** |
| * Table containing the codewords and their respective lengths. Some |
| * entries are discarded due to their lengths being too big. |
| */ |
| std::map<uint64_t, Code> valueToCode; |
| std::map<uint64_t, uint64_t> codeToValue; |
| |
| /** |
| * Entries are not inserted directly into the tree. First they are sorted |
| * based on their frequencies. |
| */ |
| struct NodeComparator |
| { |
| bool |
| operator()(const Node* lhs, const Node* rhs) const |
| { |
| return lhs->getFrequency() > rhs->getFrequency(); |
| } |
| }; |
| std::priority_queue<Node*, std::vector<Node*>, NodeComparator> trees; |
| |
| /** |
| * Build a Huffman tree using the values and their respective |
| * frequencies, which have been informed through the insertion |
| * function. |
| * |
| * @return A pointer to the root of the tree. |
| */ |
| std::unique_ptr<Node> buildTree(); |
| |
| /** |
| * Recursive function that generates the huffman codes based on |
| * the tree provided. The generated codes are added to the code |
| * map structure. |
| * |
| * @param node The node being analyzed. |
| * @param current_code The code so far. |
| */ |
| void generateCodes(const Node* node, const Code& current_code); |
| }; |
| |
| } // namespace encoder |
| } // namespace compression |
| } // namespace gem5 |
| |
| #endif //__MEM_CACHE_COMPRESSORS_ENCODERS_HUFFMAN_HH__ |