X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fintern.c;h=b8eb5198b4d9ac902ef2ce67c2fd1c994b5f0de2;hb=49aaf665f7ad1fed25d23b6ccb0da1c5461c4846;hp=0bb9277dc9172ae3aad1b801df4fba36cc606dac;hpb=f550aee00a62fe1d8baf62d83cd7efef6cc2ee92;p=pspp diff --git a/src/libpspp/intern.c b/src/libpspp/intern.c index 0bb9277dc9..b8eb5198b4 100644 --- a/src/libpspp/intern.c +++ b/src/libpspp/intern.c @@ -1,5 +1,5 @@ /* 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 @@ -22,6 +22,7 @@ #include #include "libpspp/assertion.h" +#include "libpspp/cast.h" #include "libpspp/hash-functions.h" #include "libpspp/hmap.h" @@ -32,20 +33,22 @@ struct interned_string { 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; @@ -68,16 +71,24 @@ intern_new (const char *s) 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; } @@ -92,17 +103,26 @@ intern_ref (const char *s) 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); + } } } @@ -119,3 +139,11 @@ is_interned_string (const char *s) 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; +}