/* 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 *,
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. */
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 *
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,
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;
}
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
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;
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
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);
}
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
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;
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);