Line data Source code
1 : /*************************************************************************
2 : *
3 : * Copyright (c) 2012 Kohei Yoshida
4 : *
5 : * Permission is hereby granted, free of charge, to any person
6 : * obtaining a copy of this software and associated documentation
7 : * files (the "Software"), to deal in the Software without
8 : * restriction, including without limitation the rights to use,
9 : * copy, modify, merge, publish, distribute, sublicense, and/or sell
10 : * copies of the Software, and to permit persons to whom the
11 : * Software is furnished to do so, subject to the following
12 : * conditions:
13 : *
14 : * The above copyright notice and this permission notice shall be
15 : * included in all copies or substantial portions of the Software.
16 : *
17 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 : * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 : * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 : * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 : * OTHER DEALINGS IN THE SOFTWARE.
25 : *
26 : ************************************************************************/
27 :
28 : #include "string_pool.hpp"
29 :
30 : #include "orcus/global.hpp"
31 : #include "orcus/pstring.hpp"
32 : #include "orcus/exception.hpp"
33 :
34 : #include <iostream>
35 :
36 : using namespace std;
37 :
38 : namespace {
39 :
40 : struct dump_instance : public unary_function<string*, void>
41 : {
42 0 : dump_instance() : counter(0) {}
43 0 : void operator() (const string* p)
44 : {
45 0 : cout << counter++ << ": '" << *p << "'" << endl;
46 0 : }
47 : private:
48 : size_t counter;
49 : };
50 :
51 : class pstring_back_inserter
52 : {
53 : public:
54 0 : pstring_back_inserter(vector<const string*>& store) : m_store(store) {}
55 0 : void operator() (const string* p) { m_store.push_back(p); }
56 : private:
57 : vector<const string*>& m_store;
58 : };
59 :
60 : struct pstring_less
61 : {
62 0 : bool operator() (const string* p1, const string* p2) const { return m_less(*p1, *p2); }
63 : private:
64 : less<string> m_less;
65 : };
66 :
67 : }
68 :
69 : namespace orcus {
70 :
71 0 : size_t string_pool::string_hash::operator() (const string* p) const
72 : {
73 0 : return m_hash(*p);
74 : }
75 :
76 0 : bool string_pool::string_equal_to::operator() (const string* p1, const string* p2) const
77 : {
78 0 : return m_equal_to(*p1, *p2);
79 : }
80 :
81 16 : string_pool::string_pool() {}
82 :
83 16 : string_pool::~string_pool()
84 : {
85 8 : clear();
86 8 : }
87 :
88 0 : pair<pstring, bool> string_pool::intern(const char* str)
89 : {
90 0 : return intern(str, strlen(str));
91 : }
92 :
93 0 : pair<pstring, bool> string_pool::intern(const char* str, size_t n)
94 : {
95 0 : if (!n)
96 : return pair<pstring, bool>(pstring(), false);
97 :
98 0 : unique_ptr<string> new_str(new string(str, n));
99 0 : string_store_type::const_iterator itr = m_store.find(new_str.get());
100 0 : if (itr == m_store.end())
101 : {
102 : // This string has not been interned. Intern it.
103 0 : pair<string_store_type::iterator,bool> r = m_store.insert(new_str.release());
104 0 : if (!r.second)
105 0 : throw general_error("failed to intern a new string instance.");
106 0 : const string* p = *r.first;
107 0 : assert(p->size() == n);
108 :
109 : return pair<pstring, bool>(pstring(&(*p)[0], n), true);
110 : }
111 :
112 : // This string has already been interned.
113 :
114 0 : const string* stored_str = *itr;
115 0 : assert(stored_str->size() == n);
116 0 : return pair<pstring, bool>(pstring(&(*stored_str)[0], n), false);
117 : }
118 :
119 0 : pair<pstring, bool> string_pool::intern(const pstring& str)
120 : {
121 0 : return intern(str.get(), str.size());
122 : }
123 :
124 0 : void string_pool::dump() const
125 : {
126 0 : cout << "interned string count: " << m_store.size() << endl;
127 :
128 : // Sorted stored strings first.
129 : vector<const string*> sorted;
130 0 : sorted.reserve(m_store.size());
131 0 : for_each(m_store.begin(), m_store.end(), pstring_back_inserter(sorted));
132 0 : sort(sorted.begin(), sorted.end(), pstring_less());
133 :
134 : // Now dump them all to stdout.
135 0 : for_each(sorted.begin(), sorted.end(), dump_instance());
136 0 : }
137 :
138 8 : void string_pool::clear()
139 : {
140 8 : for_each(m_store.begin(), m_store.end(), default_deleter<string>());
141 8 : m_store.clear();
142 8 : }
143 :
144 0 : size_t string_pool::size() const
145 : {
146 0 : return m_store.size();
147 : }
148 :
149 24 : }
150 :
|