/* PSPP - a program for statistical analysis.
- Copyright (C) 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010, 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 <string.h>
#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
#include "libpspp/hash-functions.h"
#include "libpspp/hmap.h"
{
struct hmap_node node; /* Node in hash table. */
size_t ref_cnt; /* Reference count. */
+ size_t length; /* strlen(string). */
char string[1]; /* Null-terminated string. */
};
/* All interned strings. */
static struct hmap interns = HMAP_INITIALIZER (interns);
-/* Searches the table of interned string for */
+/* Searches the table of interned strings for one equal to S, which has length
+ LENGTH and hash value HASH. */
static struct interned_string *
intern_lookup__ (const char *s, size_t length, unsigned int hash)
{
struct interned_string *is;
HMAP_FOR_EACH_WITH_HASH (is, struct interned_string, node, hash, &interns)
- if (!memcmp (s, is->string, length + 1))
+ if (is->length == length && !memcmp (s, is->string, length))
return is;
return NULL;
is = xmalloc (length + sizeof *is);
hmap_insert (&interns, &is->node, hash);
is->ref_cnt = 1;
+ is->length = length;
memcpy (is->string, s, length + 1);
}
return is->string;
}
+const char *
+intern_new_if_nonnull (const char *s)
+{
+ return s ? intern_new (s) : NULL;
+}
+
+
static struct interned_string *
-interned_string_from_string (const char *s)
+interned_string_from_string (const char *s_)
{
- const size_t ofs = offsetof (struct interned_string, string);
- struct interned_string *is = (struct interned_string *) (s - ofs);
+ char (*s)[1] = (char (*)[1]) s_;
+ struct interned_string *is = UP_CAST (s, struct interned_string, string);
assert (is->ref_cnt > 0);
return is;
}
return s;
}
+const char *
+intern_ref_if_nonnull (const char *s)
+{
+ return s ? intern_ref (s) : NULL;
+}
+
/* Decreases the reference count on S, which must be an interned string
returned by intern_new(). If the reference count reaches 0, frees the
interned string. */
void
intern_unref (const char *s)
{
- struct interned_string *is = interned_string_from_string (s);
- if (--is->ref_cnt == 0)
+ if (s)
{
- hmap_delete (&interns, &is->node);
- free (is);
+ struct interned_string *is = interned_string_from_string (s);
+ if (--is->ref_cnt == 0)
+ {
+ hmap_delete (&interns, &is->node);
+ free (is);
+ }
}
}
unsigned int hash = hash_bytes (s, length, 0);
return intern_lookup__ (s, length, hash) != NULL;
}
+
+/* Returns the length of S, which must be an interned string returned by
+ intern_new(). */
+size_t
+intern_strlen (const char *s)
+{
+ return interned_string_from_string (s)->length;
+}