Yuri Chornoivan contributed some typo fixes
[pspp] / src / libpspp / string-map.c
index 48124797ba570af9cdd70b61230295dc160749ce..670154fc5df63cd753d48a1d86d3da217ef89a8d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
-#include <libpspp/string-map.h>
+#include "libpspp/string-map.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/hash-functions.h>
-#include <libpspp/string-set.h>
+#include "libpspp/hash-functions.h"
+#include "libpspp/string-set.h"
 
 #include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
 
-static struct string_map_node *string_map_find_node__ (
-  const struct string_map *, const char *key, unsigned int hash);
+static struct string_map_node *string_map_find_node_with_hash (
+  const struct string_map *, const char *key, size_t length,
+  unsigned int hash);
 static bool string_map_delete__ (struct string_map *, const char *key,
                                  unsigned int hash);
 static struct string_map_node *string_map_insert__ (struct string_map *,
@@ -73,7 +75,7 @@ string_map_node_set_value_nocopy (struct string_map_node *node, char *value)
   node->value = value;
 }
 
-/* Frees NODE and and its key and value.  Ordinarily nodes are owned by
+/* Frees NODE and its key and value.  Ordinarily nodes are owned by
    string_maps, but this function should only be used by a caller that owns
    NODE, such as one that has called string_map_delete_nofree() for the
    node. */
@@ -132,6 +134,17 @@ string_map_contains (const struct string_map *map, const char *key)
   return string_map_find_node (map, key) != NULL;
 }
 
+/* If MAP contains KEY, which is LENGTH bytes long, as a key, returns the
+   corresponding value.  Otherwise, returns a null pointer. */
+const char *
+string_map_find__ (const struct string_map *map, const char *key,
+                   size_t length)
+{
+  const struct string_map_node *node = string_map_find_node__ (map, key,
+                                                               length);
+  return node != NULL ? node->value : NULL;
+}
+
 /* If MAP contains KEY as a key, returns the corresponding value.  Otherwise,
    returns a null pointer. */
 const char *
@@ -141,12 +154,22 @@ string_map_find (const struct string_map *map, const char *key)
   return node != NULL ? node->value : NULL;
 }
 
+/* If MAP contains KEY as a key, returns the corresponding node.  Otherwise,
+   returns a null pointer. */
+struct string_map_node *
+string_map_find_node__ (const struct string_map *map, const char *key,
+                        size_t length)
+{
+  return string_map_find_node_with_hash (map, key, length,
+                                         hash_bytes (key, length, 0));
+}
+
 /* If MAP contains KEY as a key, returns the corresponding node.  Otherwise,
    returns a null pointer. */
 struct string_map_node *
 string_map_find_node (const struct string_map *map, const char *key)
 {
-  return string_map_find_node__ (map, key, hash_string (key, 0));
+  return string_map_find_node__ (map, key, strlen (key));
 }
 
 /* If MAP contains KEY as a key, deletes that key's node and returns its value,
@@ -172,10 +195,13 @@ string_map_find_and_delete (struct string_map *map, const char *key)
 struct string_map_node *
 string_map_insert (struct string_map *map, const char *key, const char *value)
 {
-  unsigned int hash = hash_string (key, 0);
-  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  size_t length = strlen (key);
+  unsigned int hash = hash_bytes (key, length, 0);
+  struct string_map_node *node = string_map_find_node_with_hash (map, key,
+                                                                 length, hash);
   if (node == NULL)
-    node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+    node = string_map_insert__ (map, xmemdup0 (key, length), xstrdup (value),
+                                hash);
   return node;
 }
 
@@ -186,8 +212,10 @@ string_map_insert (struct string_map *map, const char *key, const char *value)
 struct string_map_node *
 string_map_insert_nocopy (struct string_map *map, char *key, char *value)
 {
-  unsigned int hash = hash_string (key, 0);
-  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  size_t length = strlen (key);
+  unsigned int hash = hash_bytes (key, length, 0);
+  struct string_map_node *node = string_map_find_node_with_hash (map, key,
+                                                                 length, hash);
   if (node == NULL)
     node = string_map_insert__ (map, key, value, hash);
   else
@@ -204,10 +232,13 @@ string_map_insert_nocopy (struct string_map *map, char *key, char *value)
 struct string_map_node *
 string_map_replace (struct string_map *map, const char *key, const char *value)
 {
-  unsigned int hash = hash_string (key, 0);
-  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  size_t length = strlen (key);
+  unsigned int hash = hash_bytes (key, length, 0);
+  struct string_map_node *node = string_map_find_node_with_hash (map, key,
+                                                                 length, hash);
   if (node == NULL)
-    node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+    node = string_map_insert__ (map, xmemdup0 (key, length),
+                                xstrdup (value), hash);
   else
     string_map_node_set_value (node, value);
   return node;
@@ -219,8 +250,10 @@ string_map_replace (struct string_map *map, const char *key, const char *value)
 struct string_map_node *
 string_map_replace_nocopy (struct string_map *map, char *key, char *value)
 {
-  unsigned int hash = hash_string (key, 0);
-  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  size_t length = strlen (key);
+  unsigned int hash = hash_bytes (key, length, 0);
+  struct string_map_node *node = string_map_find_node_with_hash (map, key,
+                                                                 length, hash);
   if (node == NULL)
     node = string_map_insert__ (map, key, value, hash);
   else
@@ -275,7 +308,8 @@ string_map_insert_map (struct string_map *dst, const struct string_map *src)
 
   STRING_MAP_FOR_EACH_NODE (node, src)
     {
-      if (!string_map_find_node__ (dst, node->key, node->hmap_node.hash))
+      if (!string_map_find_node_with_hash (dst, node->key, strlen (node->key),
+                                           node->hmap_node.hash))
         string_map_insert__ (dst, xstrdup (node->key), xstrdup (node->value),
                              node->hmap_node.hash);
     }
@@ -292,7 +326,9 @@ string_map_replace_map (struct string_map *dst, const struct string_map *src)
   STRING_MAP_FOR_EACH_NODE (snode, src)
     {
       struct string_map_node *dnode;
-      dnode = string_map_find_node__ (dst, snode->key, snode->hmap_node.hash);
+      dnode = string_map_find_node_with_hash (dst, snode->key,
+                                              strlen (snode->key),
+                                              snode->hmap_node.hash);
       if (dnode != NULL)
         string_map_node_set_value (dnode, snode->value);
       else
@@ -324,16 +360,35 @@ string_map_get_values (const struct string_map *map, struct string_set *values)
   STRING_MAP_FOR_EACH_VALUE (value, node, map)
     string_set_insert (values, value);
 }
+
+/* Returns true if A and B have the same content, false otherwise. */
+bool
+string_map_equals (const struct string_map *a, const struct string_map *b)
+{
+  if (string_map_count (a) != string_map_count (b))
+    return false;
+
+   const struct string_map_node *a_node;
+   STRING_MAP_FOR_EACH_NODE (a_node, a)
+     {
+       const struct string_map_node *b_node = string_map_find_node_with_hash (
+         b, a_node->key, strlen (a_node->key), a_node->hmap_node.hash);
+       if (!b_node || strcmp (a_node->value, b_node->value))
+         return false;
+     }
+
+   return true;
+}
 \f
 static struct string_map_node *
-string_map_find_node__ (const struct string_map *map, const char *key,
-                        unsigned int hash)
+string_map_find_node_with_hash (const struct string_map *map, const char *key,
+                                size_t length, unsigned int hash)
 {
   struct string_map_node *node;
 
   HMAP_FOR_EACH_WITH_HASH (node, struct string_map_node, hmap_node,
                            hash, &map->hmap)
-    if (!strcmp (key, node->key))
+    if (!strncmp (key, node->key, length) && node->key[length] == '\0')
       return node;
 
   return NULL;
@@ -343,7 +398,8 @@ static bool
 string_map_delete__ (struct string_map *map, const char *key,
                      unsigned int hash)
 {
-  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  struct string_map_node *node
+    = string_map_find_node_with_hash (map, key, strlen (key), hash);
   if (node != NULL)
     {
       string_map_delete_node (map, node);