diff options
author | David Adam <zanchey@ucc.gu.uwa.edu.au> | 2015-07-26 10:20:13 +0800 |
---|---|---|
committer | David Adam <zanchey@ucc.gu.uwa.edu.au> | 2015-07-26 10:20:13 +0800 |
commit | 3929e9de0e69666b37df87347d5ce15663e81347 (patch) | |
tree | b2701c439c0260840ce1c68beaebf7de1178cc53 /src/intern.cpp | |
parent | 793e1afa084982dac92c4fe19e50c25e326a79c2 (diff) | |
parent | f4d1657c22c81a7720a91026f915b80d2d6aa6e8 (diff) |
Merge branch 'master' into iwyu
Diffstat (limited to 'src/intern.cpp')
-rw-r--r-- | src/intern.cpp | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/intern.cpp b/src/intern.cpp new file mode 100644 index 00000000..2ec0af8a --- /dev/null +++ b/src/intern.cpp @@ -0,0 +1,86 @@ +/** \file intern.c + + Library for pooling common strings + +*/ +#include "config.h" // IWYU pragma: keep + +#include <wchar.h> +#include <pthread.h> +#include <vector> +#include <algorithm> + +#include "fallback.h" // IWYU pragma: keep +#include "common.h" +#include "intern.h" + +/** Comparison function for intern'd strings */ +class string_table_compare_t +{ +public: + bool operator()(const wchar_t *a, const wchar_t *b) const + { + return wcscmp(a, b) < 0; + } +}; + +/* A sorted vector ends up being a little more memory efficient than a std::set for the intern'd string table */ +#define USE_SET 0 +#if USE_SET +/** The table of intern'd strings */ +typedef std::set<const wchar_t *, string_table_compare_t> string_table_t; +#else +/** The table of intern'd strings */ +typedef std::vector<const wchar_t *> string_table_t; +#endif + +static string_table_t string_table; + +/** The lock to provide thread safety for intern'd strings */ +static pthread_mutex_t intern_lock = PTHREAD_MUTEX_INITIALIZER; + +static const wchar_t *intern_with_dup(const wchar_t *in, bool dup) +{ + if (!in) + return NULL; + +// debug( 0, L"intern %ls", in ); + scoped_lock lock(intern_lock); + const wchar_t *result; + +#if USE_SET + 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); + } +#else + string_table_t::iterator iter = std::lower_bound(string_table.begin(), string_table.end(), in, string_table_compare_t()); + if (iter != string_table.end() && wcscmp(*iter, in) == 0) + { + result = *iter; + } + else + { + result = dup ? wcsdup(in) : in; + string_table.insert(iter, result); + } +#endif + return result; +} + +const wchar_t *intern(const wchar_t *in) +{ + return intern_with_dup(in, true); +} + + +const wchar_t *intern_static(const wchar_t *in) +{ + return intern_with_dup(in, false); +} |