From 2fbe5393df3c62ce174d3fa91ce7776a60ac2159 Mon Sep 17 00:00:00 2001 From: clyne Date: Sun, 15 Nov 2020 18:55:40 -0500 Subject: [PATCH] prevent compression if it doesn't save space --- consteval_huffman.hpp | 70 +++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/consteval_huffman.hpp b/consteval_huffman.hpp index 6061764..7bb0ce5 100644 --- a/consteval_huffman.hpp +++ b/consteval_huffman.hpp @@ -1,4 +1,3 @@ - /** * consteval_huffman.hpp - Provides compile-time text compression. * Written by Clyne Sullivan. @@ -216,12 +215,18 @@ private: 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: + 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. class decode_info { public: @@ -230,8 +235,12 @@ public: // Checks if another byte is available operator bool() const { - const auto [size_bytes, last_bits] = m_data.compressed_size_info(); - return m_pos < (size_bytes - 1) || m_bit > (8 - last_bits); + if constexpr (bytes_saved() > 0) { + 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 @@ -245,14 +254,18 @@ public: private: // Internal: moves to next byte void get_next() { - auto *node = m_data.decode_tree; - do { - bool bit = m_data.compressed_data[m_pos] & (1 << (m_bit - 1)); - if (--m_bit == 0) - m_bit = 8, m_pos++; - node += 3 * node[bit ? 2 : 1]; - } while (node[1] != 0); - m_current = *node; + if constexpr (bytes_saved() > 0) { + auto *node = m_data.decode_tree; + do { + bool bit = m_data.compressed_data[m_pos] & (1 << (m_bit - 1)); + if (--m_bit == 0) + m_bit = 8, m_pos++; + node += 3 * node[bit ? 2 : 1]; + } while (node[1] != 0); + m_current = *node; + } else { + m_current = data[m_pos++]; + } } const huffman_compress& m_data; @@ -264,25 +277,24 @@ public: }; consteval huffman_compress() { - build_decode_tree(); - compress(); - } - - consteval static auto compressed_size() { - 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(); + if constexpr (bytes_saved() > 0) { + build_decode_tree(); + compress(); + } else { + std::copy(data, data + data_length, compressed_data); + } } // Creates a decoder object for iteratively decompressing the data. auto get_decoder() const { 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_ -