prevent compression if it doesn't save space

pull/1/head
Clyne 4 years ago committed by GitHub
parent e58cd38132
commit 2fbe5393df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,3 @@
/** /**
* consteval_huffman.hpp - Provides compile-time text compression. * consteval_huffman.hpp - Provides compile-time text compression.
* Written by Clyne Sullivan. * Written by Clyne Sullivan.
@ -216,12 +215,18 @@ private:
delete[] tree.data(); delete[] tree.data();
} }
// Contains the compressed data.
unsigned char compressed_data[compressed_size_info().first] = {};
// Contains a 'tree' that can be used to decompress the data.
unsigned char decode_tree[3 * tree_count()] = {};
public: public:
consteval static auto compressed_size() {
return compressed_size_info().first + 3 * tree_count();
}
consteval static auto uncompressed_size() {
return data_length;
}
consteval static size_t bytes_saved() {
size_t diff = uncompressed_size() - compressed_size();
return diff > 0 ? diff : 0;
}
// Utility for decoding compressed data. // Utility for decoding compressed data.
class decode_info { class decode_info {
public: public:
@ -230,8 +235,12 @@ public:
// Checks if another byte is available // Checks if another byte is available
operator bool() const { operator bool() const {
const auto [size_bytes, last_bits] = m_data.compressed_size_info(); if constexpr (bytes_saved() > 0) {
return m_pos < (size_bytes - 1) || m_bit > (8 - last_bits); const auto [size_bytes, last_bits] = m_data.compressed_size_info();
return m_pos < (size_bytes - 1) || m_bit > (8 - last_bits);
} else {
return m_pos < data_length;
}
} }
// Gets the current byte // Gets the current byte
@ -245,14 +254,18 @@ public:
private: private:
// Internal: moves to next byte // Internal: moves to next byte
void get_next() { void get_next() {
auto *node = m_data.decode_tree; if constexpr (bytes_saved() > 0) {
do { auto *node = m_data.decode_tree;
bool bit = m_data.compressed_data[m_pos] & (1 << (m_bit - 1)); do {
if (--m_bit == 0) bool bit = m_data.compressed_data[m_pos] & (1 << (m_bit - 1));
m_bit = 8, m_pos++; if (--m_bit == 0)
node += 3 * node[bit ? 2 : 1]; m_bit = 8, m_pos++;
} while (node[1] != 0); node += 3 * node[bit ? 2 : 1];
m_current = *node; } while (node[1] != 0);
m_current = *node;
} else {
m_current = data[m_pos++];
}
} }
const huffman_compress<data>& m_data; const huffman_compress<data>& m_data;
@ -264,25 +277,24 @@ public:
}; };
consteval huffman_compress() { consteval huffman_compress() {
build_decode_tree(); if constexpr (bytes_saved() > 0) {
compress(); build_decode_tree();
} compress();
} else {
consteval static auto compressed_size() { std::copy(data, data + data_length, compressed_data);
return sizeof(compressed_data) + sizeof(decode_tree); }
}
consteval static auto uncompressed_size() {
return data_length;
}
consteval static size_t bytes_saved() {
return uncompressed_size() - compressed_size();
} }
// Creates a decoder object for iteratively decompressing the data. // Creates a decoder object for iteratively decompressing the data.
auto get_decoder() const { auto get_decoder() const {
return decode_info(*this); return decode_info(*this);
} }
private:
// Contains the compressed data.
unsigned char compressed_data[bytes_saved() > 0 ? compressed_size_info().first : data_length] = {};
// Contains a 'tree' that can be used to decompress the data.
unsigned char decode_tree[3 * tree_count()] = {};
}; };
#endif // TCSULLIVAN_CONSTEVAL_HUFFMAN_HPP_ #endif // TCSULLIVAN_CONSTEVAL_HUFFMAN_HPP_

Loading…
Cancel
Save