blob: 7a47aa93e8ef6a61e7a4c74e840cb1c91aa50e5d [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.
*/
#include "mem/cache/compressors/encoders/huffman.hh"
#include <cassert>
#include "base/logging.hh"
namespace gem5
{
GEM5_DEPRECATED_NAMESPACE(Compressor, compression);
namespace compression
{
GEM5_DEPRECATED_NAMESPACE(Encoder, encoder);
namespace encoder
{
Huffman::Huffman(uint64_t max_code_length)
: Base(), maxCodeLength(max_code_length)
{
fatal_if(maxCodeLength > 64,
"Code length cannot surpass its underlying container");
}
void
Huffman::sample(uint64_t value, uint64_t frequency)
{
if (frequency != 0) {
trees.push(new Node(value, frequency));
}
}
std::unique_ptr<Huffman::Node>
Huffman::buildTree()
{
// Construct tree by assigning left and right nodes. The left path leads
// to the most frequent values
while (trees.size() > 1) {
Node* left = trees.top();
trees.pop();
Node* right = trees.top();
trees.pop();
Node* parent = new Node(left, right);
trees.push(parent);
}
// All queue entries have been merged into a single entry containing
// the tree
Node* root = trees.top();
trees.pop();
return std::unique_ptr<Node>(root);
}
void
Huffman::generateCodeMaps()
{
valueToCode.clear();
codeToValue.clear();
generateCodes(buildTree().get(), Code());
}
void
Huffman::generateCodes(const Node* node, const Code& current_code)
{
// Drop all entries with length greater than maxCodeLength
if (current_code.length > maxCodeLength) {
return;
}
if (node->isLeaf()) {
valueToCode[node->getValue()] = current_code;
codeToValue[current_code.code] = node->getValue();
} else {
Code right_code = current_code;
right_code.code = (right_code.code << 1) + 1;
right_code.length++;
generateCodes(node->getRightSubTree(), right_code);
Code left_code = current_code;
left_code.code = left_code.code << 1;
left_code.length++;
generateCodes(node->getLeftSubTree(), left_code);
}
}
Code
Huffman::encode(const uint64_t val) const
{
auto it = valueToCode.find(val);
if (it == valueToCode.end()) {
// If the value is unknown, generate a dummy code with invalid
// length to let the caller know the encoding is invalid
Code dummy_code;
dummy_code.code = 0;
dummy_code.length = 65;
return dummy_code;
} else {
return it->second;
}
}
uint64_t
Huffman::decode(const uint64_t code) const
{
// A code that does not exist cannot be decoded
auto it = codeToValue.find(code);
assert(it != codeToValue.end());
return it->second;
}
} // namespace encoder
} // namespace compression
} // namespace gem5