aboutsummaryrefslogtreecommitdiffhomepage
path: root/intern.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-01-23 20:02:15 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-01-23 20:02:15 -0800
commitfa569b32fb925353057f9c0342b7b50009ed38f0 (patch)
tree99a73b951d422605aef41bfb9a94104d7f418083 /intern.cpp
parent78f8317de8507dbd5957922619d657348351f08e (diff)
Made intern'd strings thread safe.
Removed intern_free_all().
Diffstat (limited to 'intern.cpp')
-rw-r--r--intern.cpp126
1 files changed, 29 insertions, 97 deletions
diff --git a/intern.cpp b/intern.cpp
index 2fed376f..ced8be9f 100644
--- a/intern.cpp
+++ b/intern.cpp
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <wchar.h>
#include <unistd.h>
+#include <set>
#include "fallback.h"
#include "util.h"
@@ -18,112 +19,43 @@
#include "common.h"
#include "intern.h"
-/**
- Table of interned strings
-*/
-static hash_table_t *intern_table=0;
-
-/**
- Table of static interned strings
-*/
-static hash_table_t *intern_static_table=0;
+/** Comparison function for intern'd strings */
+static bool string_table_compare(const wchar_t *a, const wchar_t *b) {
+ return wcscmp(a, b) < 0;
+}
-const wchar_t *intern( const wchar_t *in )
-{
- ASSERT_IS_MAIN_THREAD();
- const wchar_t *res=0;
+/** The table of intern'd strings */
+typedef std::set<const wchar_t *, bool (*)(const wchar_t *, const wchar_t *b)> string_table_t;
+static string_table_t string_table(string_table_compare);
-// debug( 0, L"intern %ls", in );
-
- if( !in )
- return 0;
-
- if( !intern_table )
- {
- intern_table = (hash_table_t *)malloc( sizeof( hash_table_t ) );
- if( !intern_table )
- {
- DIE_MEM();
- }
- hash_init( intern_table, &hash_wcs_func, &hash_wcs_cmp );
- }
-
- if( intern_static_table )
- {
- res = (const wchar_t *)hash_get( intern_static_table, in );
- }
-
- if( !res )
- {
- res = (const wchar_t *)hash_get( intern_table, in );
-
- if( !res )
- {
- res = wcsdup( in );
- if( !res )
- {
- DIE_MEM();
- }
-
- hash_put( intern_table, res, res );
- }
- }
-
- return res;
-}
+/** The lock to provide thread safety for intern'd strings */
+static pthread_mutex_t intern_lock = PTHREAD_MUTEX_INITIALIZER;
-const wchar_t *intern_static( const wchar_t *in )
+static const wchar_t *intern_with_dup( const wchar_t *in, bool dup )
{
- const wchar_t *res=0;
-
if( !in )
- return 0;
-
- if( !intern_static_table )
- {
- intern_static_table = (hash_table_t *)malloc( sizeof( hash_table_t ) );
- if( !intern_static_table )
- {
- DIE_MEM();
- }
- hash_init( intern_static_table, &hash_wcs_func, &hash_wcs_cmp );
- }
-
- res = (const wchar_t *)hash_get( intern_static_table, in );
-
- if( !res )
- {
- res = in;
- hash_put( intern_static_table, res, res );
- }
-
- return res;
+ return NULL;
+
+// debug( 0, L"intern %ls", in );
+ scoped_lock lock(intern_lock);
+ const wchar_t *result;
+ string_table_t::const_iterator iter = string_table.find(in);
+ if (iter != string_table.end()) {
+ result = *iter;
+ } else {
+ result = dup ? wcsdup(in) : in;
+ string_table.insert(result);
+ }
+ return result;
}
-/**
- Free the specified key/value pair. Should only be called by intern_free_all at shutdown
-*/
-static void clear_value( void *key, void *data )
+const wchar_t *intern( const wchar_t *in )
{
- debug( 3, L"interned string: '%ls'", data );
- free( (void *)data );
+ return intern_with_dup(in, true);
}
-void intern_free_all()
-{
- if( intern_table )
- {
- hash_foreach( intern_table, &clear_value );
- hash_destroy( intern_table );
- free( intern_table );
- intern_table=0;
- }
- if( intern_static_table )
- {
- hash_destroy( intern_static_table );
- free( intern_static_table );
- intern_static_table=0;
- }
-
+const wchar_t *intern_static( const wchar_t *in )
+{
+ return intern_with_dup(in, false);
}