/*- * Copyright (c) 2003-2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libpmcstat.h" static LIST_HEAD(,pmcstat_string) pmcstat_string_hash[PMCSTAT_NHASH]; /* * Intern a copy of string 's', and return a pointer to the * interned structure. */ pmcstat_interned_string pmcstat_string_intern(const char *s) { struct pmcstat_string *ps; const struct pmcstat_string *cps; int hash, len; if ((cps = pmcstat_string_lookup(s)) != NULL) return (cps); hash = pmcstat_string_compute_hash(s); len = strlen(s); if ((ps = malloc(sizeof(*ps))) == NULL) err(EX_OSERR, "ERROR: Could not intern string"); ps->ps_len = len; ps->ps_hash = hash; ps->ps_string = strdup(s); LIST_INSERT_HEAD(&pmcstat_string_hash[hash], ps, ps_next); return ((pmcstat_interned_string) ps); } const char * pmcstat_string_unintern(pmcstat_interned_string str) { const char *s; s = ((const struct pmcstat_string *) str)->ps_string; return (s); } /* * Compute a 'hash' value for a string. */ int pmcstat_string_compute_hash(const char *s) { unsigned hash; for (hash = 2166136261; *s; s++) hash = (hash ^ *s) * 16777619; return (hash & PMCSTAT_HASH_MASK); } pmcstat_interned_string pmcstat_string_lookup(const char *s) { struct pmcstat_string *ps; int hash, len; hash = pmcstat_string_compute_hash(s); len = strlen(s); LIST_FOREACH(ps, &pmcstat_string_hash[hash], ps_next) if (ps->ps_len == len && ps->ps_hash == hash && strcmp(ps->ps_string, s) == 0) return (ps); return (NULL); } int pmcstat_string_lookup_hash(pmcstat_interned_string s) { const struct pmcstat_string *ps; ps = (const struct pmcstat_string *) s; return (ps->ps_hash); } /* * Destroy the string table, free'ing up space. */ void pmcstat_string_shutdown(void) { int i; struct pmcstat_string *ps, *pstmp; for (i = 0; i < PMCSTAT_NHASH; i++) LIST_FOREACH_SAFE(ps, &pmcstat_string_hash[i], ps_next, pstmp) { LIST_REMOVE(ps, ps_next); free(ps->ps_string); free(ps); } } /* * Initialize the string interning facility. */ void pmcstat_string_initialize(void) { int i; for (i = 0; i < PMCSTAT_NHASH; i++) LIST_INIT(&pmcstat_string_hash[i]); }