/* * shstr.C: Shared string class * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. */ static char const rcsid[] = "$Id: shstr.C,v 1.3 2007/09/22 14:27:30 pippijn dead $"; #include shstr::shstr (char const * const str) { insert (str); } shstr::shstr (const shstr &rhs) { insert (rhs.m_str); } shstr::~shstr () { erase (); } char const * const shstr::c_str () const { return m_str; } shstr::size_type shstr::length () const { return m_len; } shstr & shstr::operator = (char const * const rhs) { erase (); insert (rhs); return *this; } shstr & shstr::operator = (const shstr &rhs) { if (m_str == rhs.m_str) return *this; erase (); insert (rhs.m_str); return *this; } bool shstr::operator == (const shstr &rhs) const { return m_str == rhs.m_str; } bool shstr::operator != (const shstr &rhs) const { return m_str != rhs.m_str; } // string manager functions shentry * shstr::prepare (char const * const str) { size_t n = hash (str); pairs::iterator it = find (str, n); shentry *entry; if (it == m_buckets[n].end ()) { entry = new shentry (str, n); m_buckets[n].push_back (entry); } else entry = *it; return entry; } bool shstr::unref (char const * const str) { size_t n = hash (str); pairs::iterator it = find (str, n); if (it == m_buckets[n].end ()) return false; else { shentry *entry = *it; --entry->m_refcnt; if (entry->m_refcnt == 0) { m_buckets[n].erase (it); delete entry; return true; } else return false; } } const shentry * shstr::get (char const * const str) { size_t n = hash (str); pairs::iterator it = find (str, n); if (it == m_buckets[n].end ()) return NULL; else return *it; } shstr::pairs::iterator shstr::find (char const * const str, size_t n) { pairs &bucket = m_buckets[n]; pairs::iterator it = bucket.begin (); pairs::iterator et = bucket.end (); while (it != et) { /* we first check hash equality, because if the hash is not * equal, then the string most definately is not */ if (n == (*it)->m_hash && __builtin_expect (!strcmp ((*it)->m_str, str), 0)) return it; ++it; } return et; } size_t shstr::hash (char const * const str) { char const *s = str; unsigned long hash = 0; // use the one-at-a-time hash function // see http://burtleburtle.net/bob/hash/doobs.html while (*s) { hash += *s++; hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash % m_bucketcnt; } char const * const shstr::insert (char const * const str, size_t *size) { shentry *entry = prepare (str); ++entry->m_refcnt; if (entry->m_refcnt == 1) ++m_cnt; *size = entry->m_len; return entry->m_str; } void shstr::erase (char const * const str) { bool removed = unref (str); if (removed) --m_cnt; } size_t shstr::refs (char const * const str) { const shentry *entry = get (str); if (entry == NULL) return 0; else return entry->m_refcnt; } size_t shstr::strcnt () { return m_cnt; } size_t shstr::m_cnt = 0; size_t shstr::m_bucketcnt = 1024; shstr::pairs *shstr::m_buckets;