blob: 3f29f2c264416f11a215d99ed5c60f93befca6e3 [file] [log] [blame]
/*
* 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__