hash table CHANGE new debug category for hash table changes

Fixes #963
diff --git a/src/hash_table.c b/src/hash_table.c
index f7d4378..fe0d68e 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -606,6 +606,73 @@
     return 1;
 }
 
+/* prints little-endian numbers, will also work on big-endian just the values will look weird */
+static char *
+lyht_dbgprint_val2str(void *val_p, int32_t hits, uint16_t rec_size)
+{
+    char *val;
+    int32_t i, j, val_size;
+
+    val_size = rec_size - (sizeof(struct ht_rec) - 1);
+
+    val = malloc(val_size * 2 + 1);
+    for (i = 0, j = val_size - 1; i < val_size; ++i, --j) {
+        if (hits > 0) {
+            sprintf(val + i * 2, "%02x", *(((uint8_t *)val_p) + j));
+        } else {
+            sprintf(val + i * 2, "  ");
+        }
+    }
+
+    return val;
+}
+
+static void
+lyht_dbgprint_ht(struct hash_table *ht, const char *info)
+{
+    struct ht_rec *rec;
+    uint32_t i, i_len;
+    char *val;
+
+    if (LY_LLDBG > ly_log_level) {
+        return;
+    }
+
+    LOGDBG(LY_LDGHASH, "");
+    LOGDBG(LY_LDGHASH, "hash table %s (used %u, size %u):", info, ht->used, ht->size);
+
+    val = malloc(11);
+    sprintf(val, "%u", ht->size);
+    i_len = strlen(val);
+    free(val);
+
+    for (i = 0; i < ht->size; ++i) {
+        rec = lyht_get_rec(ht->recs, ht->rec_size, i);
+        val = lyht_dbgprint_val2str(&rec->val, rec->hits, ht->rec_size);
+        if (rec->hits > 0) {
+            LOGDBG(LY_LDGHASH, "[%*u] val  %s  hash  %10u %% %*u  hits  %2d",
+                   (int)i_len, i, val, rec->hash, (int)i_len, rec->hash & (ht->size - 1), rec->hits);
+        } else {
+            LOGDBG(LY_LDGHASH, "[%*u] val  %s  hash  %10s %% %*s  hits  %2d",
+                   (int)i_len, i, val, "", (int)i_len, "", rec->hits);
+        }
+        free(val);
+    }
+    LOGDBG(LY_LDGHASH, "");
+}
+
+static void
+lyht_dbgprint_value(void *val_p, uint32_t hash, uint16_t rec_size, const char *operation)
+{
+    if (LY_LLDBG > ly_log_level) {
+        return;
+    }
+
+    char *val = lyht_dbgprint_val2str(val_p, 1, rec_size);
+    LOGDBG(LY_LDGHASH, "%s value %s with hash %u", operation, val, hash);
+    free(val);
+}
+
 int
 lyht_insert_with_resize_cb(struct hash_table *ht, void *val_p, uint32_t hash,
                            values_equal_cb resize_val_equal, void **match_p)
@@ -615,6 +682,9 @@
     int r, ret;
     values_equal_cb old_val_equal;
 
+    lyht_dbgprint_ht(ht, "before");
+    lyht_dbgprint_value(val_p, hash, ht->rec_size, "inserting");
+
     if (!lyht_find_first(ht, hash, &rec)) {
         /* we found matching shortened hash */
         if ((rec->hash == hash) && ht->val_equal(val_p, &rec->val, 1, ht->cb_data)) {
@@ -688,6 +758,8 @@
             }
         }
     }
+
+    lyht_dbgprint_ht(ht, "after");
     return ret;
 }
 
@@ -704,8 +776,12 @@
     int32_t i;
     int first_matched = 0, r, ret;
 
+    lyht_dbgprint_ht(ht, "before");
+    lyht_dbgprint_value(val_p, hash, ht->rec_size, "removing");
+
     if (lyht_find_first(ht, hash, &rec)) {
         /* hash not found */
+        LOGDBG(LY_LDGHASH, "remove failed");
         return 1;
     }
     if ((rec->hash == hash) && ht->val_equal(val_p, &rec->val, 1, ht->cb_data)) {
@@ -743,6 +819,7 @@
     } else {
         /* value not found even in collisions */
         assert(!first_matched);
+        LOGDBG(LY_LDGHASH, "remove failed");
         return 1;
     }
 
@@ -757,5 +834,6 @@
         }
     }
 
+    lyht_dbgprint_ht(ht, "after");
     return ret;
 }
diff --git a/src/hash_table.h b/src/hash_table.h
index 84ea07e..b9323c0 100644
--- a/src/hash_table.h
+++ b/src/hash_table.h
@@ -60,8 +60,8 @@
  */
 struct ht_rec {
     uint32_t hash;        /* hash of the value */
-    int32_t hits;         /* collision/overflow value count - 1 (a filled entry has 1 hit,
-                           * special value -1 means a deleted record) */
+    int32_t hits;         /* (collision/overflow value count - 1) (a filled entry has 1 hit),
+                           * special value (-1) means a deleted record) */
     unsigned char val[1]; /* arbitrary-size value */
 } _PACKED;
 
@@ -87,7 +87,7 @@
 struct dict_rec {
     char *value;
     uint32_t refcount;
-};
+} _PACKED;
 
 /**
  * dictionary to store repeating strings
diff --git a/src/libyang.h.in b/src/libyang.h.in
index d0cd8d7..8f51c1d 100644
--- a/src/libyang.h.in
+++ b/src/libyang.h.in
@@ -1916,6 +1916,7 @@
 #define LY_LDGXPATH 0x08 /**< XPath parsing end evaluation. */
 #define LY_LDGDIFF  0x10 /**< Diff processing and creation. */
 #define LY_LDGAPI   0x20 /**< API tracing. */
+#define LY_LDGHASH  0x40 /**< Hash table modifications. */
 
 /**
  * @}
diff --git a/src/log.c b/src/log.c
index 54976c9..eff2f60 100644
--- a/src/log.c
+++ b/src/log.c
@@ -266,6 +266,9 @@
     case LY_LDGAPI:
         str_group = "API";
         break;
+    case LY_LDGHASH:
+        str_group = "HASH";
+        break;
     default:
         LOGINT(NULL);
         return;
diff --git a/tests/internal/test_hash_table.c b/tests/internal/test_hash_table.c
index 46f4c21..9ea2fcb 100755
--- a/tests/internal/test_hash_table.c
+++ b/tests/internal/test_hash_table.c
@@ -364,5 +364,7 @@
         cmocka_unit_test_setup_teardown(test_invalid_move2, setup_f, teardown_f),
     };
 
+    /*ly_verb(LY_LLDBG);
+    ly_verb_dbg(LY_LDGHASH);*/
     return cmocka_run_group_tests(tests, NULL, NULL);
 }