add helper for compressing arrays; support unsigned data

master
Clyne 3 years ago committed by GitHub
parent 58cdbb6a1b
commit 6b2828c6f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,13 +17,15 @@ namespace detail
// Provides a string container for the huffman compressor. // Provides a string container for the huffman compressor.
// Using this allows for automatic string data length measurement, as // Using this allows for automatic string data length measurement, as
// well as implementation of the _huffman suffix. // well as implementation of the _huffman suffix.
template<unsigned long int N> template<typename T, unsigned long int N>
requires(std::same_as<std::remove_cvref_t<T>, char> ||
std::same_as<std::remove_cvref_t<T>, unsigned char>)
struct huffman_string_container { struct huffman_string_container {
char data[N]; T data[N];
consteval huffman_string_container(const char (&s)[N]) noexcept { consteval huffman_string_container(const T (&s)[N]) noexcept {
std::copy(s, s + N, data); std::copy(s, s + N, data);
} }
consteval operator const char *() const noexcept { consteval operator const T *() const noexcept {
return data; return data;
} }
consteval auto size() const noexcept { consteval auto size() const noexcept {
@ -35,12 +37,13 @@ namespace detail
/** /**
* Compresses the given data string using Huffman coding, providing a * Compresses the given data string using Huffman coding, providing a
* minimal run-time interface for decompressing the data. * minimal run-time interface for decompressing the data.
* @tparam data The string of data to be compressed. * @tparam raw_data The string of data to be compressed.
*/ */
template<auto raw_data> template<auto raw_data>
requires( requires(
std::same_as<std::remove_cvref_t<decltype(raw_data)>, std::same_as<std::remove_cvref_t<decltype(raw_data)>,
detail::huffman_string_container<raw_data.size()>> && detail::huffman_string_container<std::remove_cvref_t<decltype(raw_data.data[0])>,
raw_data.size()>> &&
raw_data.size() > 0) raw_data.size() > 0)
class huffman_compressor class huffman_compressor
{ {
@ -167,8 +170,9 @@ private:
size_t bytes = 1, bits = 0; size_t bytes = 1, bits = 0;
for (usize_t i = 0; i < raw_data.size(); i++) { for (usize_t i = 0; i < raw_data.size(); i++) {
auto c = static_cast<int>(raw_data[i]);
auto leaf = std::find_if(tree.begin(), tree.end(), auto leaf = std::find_if(tree.begin(), tree.end(),
[c = raw_data[i]](const auto& n) { return n.value == c; }); [c](const auto& n) { return n.value == c; });
while (leaf->parent != -1) { while (leaf->parent != -1) {
if (++bits == 8) if (++bits == 8)
@ -197,8 +201,9 @@ private:
// Compress data backwards, because we obtain the Huffman codes backwards // Compress data backwards, because we obtain the Huffman codes backwards
// as we traverse towards the parent node. // as we traverse towards the parent node.
for (auto i = raw_data.size(); i > 0; i--) { for (auto i = raw_data.size(); i > 0; i--) {
auto c = static_cast<int>(raw_data[i - 1]);
auto leaf = std::find_if(tree.begin(), tree.end(), auto leaf = std::find_if(tree.begin(), tree.end(),
[c = raw_data[i - 1]](auto& n) { return n.value == c; }); [c](auto& n) { return n.value == c; });
while (leaf->parent != -1) { while (leaf->parent != -1) {
auto parent = tree.begin() + leaf->parent; auto parent = tree.begin() + leaf->parent;
@ -282,7 +287,9 @@ public:
} }
bool operator==(const decoder& other) const noexcept { bool operator==(const decoder& other) const noexcept {
return m_data == other.m_data && m_bit == other.m_bit; return m_data == other.m_data &&
m_bit == other.m_bit &&
m_current == other.m_current;
} }
auto operator*() const noexcept { auto operator*() const noexcept {
return m_current; return m_current;
@ -299,8 +306,12 @@ public:
private: private:
void get_next() noexcept { void get_next() noexcept {
if (*this == end(m_data)) if (auto e = end(m_table - compressed_size_info().first);
m_data == e.m_data && m_bit == e.m_bit)
{
m_current = -1;
return; return;
}
if constexpr (bytes_saved() > 0) { if constexpr (bytes_saved() > 0) {
auto *node = m_table; auto *node = m_table;
int data = *m_data; int data = *m_data;
@ -376,4 +387,7 @@ constexpr auto operator ""_huffman()
return huffman_compressor<hsc>(); return huffman_compressor<hsc>();
} }
template <detail::huffman_string_container hsc>
constexpr auto huffman_compress = huffman_compressor<hsc>();
#endif // TCSULLIVAN_CONSTEVAL_HUFFMAN_HPP_ #endif // TCSULLIVAN_CONSTEVAL_HUFFMAN_HPP_

Loading…
Cancel
Save