]> code.bitgloo.com Git - clyne/consteval-huffman.git/commitdiff
add helper for compressing arrays; support unsigned data
authorclyne <clyne@bitgloo.com>
Mon, 11 Oct 2021 19:27:54 +0000 (15:27 -0400)
committerGitHub <noreply@github.com>
Mon, 11 Oct 2021 19:27:54 +0000 (15:27 -0400)
include/consteval_huffman/consteval_huffman.hpp

index 7884e2fb024b63bb132d0054f859295863a08fb2..0c41913f895a3f34f164413a13fd401f0f4c5156 100644 (file)
@@ -17,13 +17,15 @@ namespace detail
     // Provides a string container for the huffman compressor.
     // Using this allows for automatic string data length measurement, as
     // 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 {
-        char data[N];
-        consteval huffman_string_container(const char (&s)[N]) noexcept {
+        T data[N];
+        consteval huffman_string_container(const T (&s)[N]) noexcept {
             std::copy(s, s + N, data);
         }
-        consteval operator const char *() const noexcept {
+        consteval operator const T *() const noexcept {
             return data;
         }
         consteval auto size() const noexcept {
@@ -35,12 +37,13 @@ namespace detail
 /**
  * Compresses the given data string using Huffman coding, providing a
  * 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>
     requires(
         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)
 class huffman_compressor
 {
@@ -167,8 +170,9 @@ private:
         size_t bytes = 1, bits = 0;
 
         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(),
-                [c = raw_data[i]](const auto& n) { return n.value == c; });
+                [c](const auto& n) { return n.value == c; });
 
             while (leaf->parent != -1) {
                 if (++bits == 8)
@@ -197,8 +201,9 @@ private:
         // Compress data backwards, because we obtain the Huffman codes backwards
         // as we traverse towards the parent node.
         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(),
-                [c = raw_data[i - 1]](auto& n) { return n.value == c; });
+                [c](auto& n) { return n.value == c; });
 
             while (leaf->parent != -1) {
                 auto parent = tree.begin() + leaf->parent;
@@ -282,7 +287,9 @@ public:
         }
 
         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 {
             return m_current;
@@ -299,8 +306,12 @@ public:
 
     private:
         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;
+            }
             if constexpr (bytes_saved() > 0) {
                 auto *node = m_table;
                 int data = *m_data;
@@ -376,4 +387,7 @@ constexpr auto operator ""_huffman()
     return huffman_compressor<hsc>();
 }
 
+template <detail::huffman_string_container hsc>
+constexpr auto huffman_compress = huffman_compressor<hsc>();
+
 #endif // TCSULLIVAN_CONSTEVAL_HUFFMAN_HPP_