Line data Source code
1 : /*************************************************************************
2 : *
3 : * Copyright (c) 2010 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 "orcus/pstring.hpp"
29 : #include "string_pool.hpp"
30 :
31 : #include <cassert>
32 : #include <iostream>
33 : #include <vector>
34 :
35 : #include <boost/thread/mutex.hpp>
36 :
37 : using namespace std;
38 :
39 : namespace orcus {
40 :
41 : namespace {
42 :
43 : /**
44 : * Internal cache to store interned string instances.
45 : */
46 16 : struct _interned_strings {
47 : string_pool store;
48 : ::boost::mutex mtx;
49 8 : } interned_strings;
50 :
51 : }
52 :
53 0 : pstring pstring::intern(const char* str)
54 : {
55 0 : return intern(str, strlen(str));
56 : }
57 :
58 0 : pstring pstring::intern(const char* str, size_t n)
59 : {
60 : ::boost::mutex::scoped_lock lock(interned_strings.mtx);
61 0 : return interned_strings.store.intern(str, n).first;
62 : }
63 :
64 0 : void pstring::intern::dispose()
65 : {
66 : ::boost::mutex::scoped_lock lock(interned_strings.mtx);
67 0 : interned_strings.store.clear();
68 0 : }
69 :
70 0 : size_t pstring::intern::size()
71 : {
72 : ::boost::mutex::scoped_lock lock(interned_strings.mtx);
73 0 : return interned_strings.store.size();
74 : }
75 :
76 0 : void pstring::intern::dump()
77 : {
78 : ::boost::mutex::scoped_lock lock(interned_strings.mtx);
79 0 : interned_strings.store.dump();
80 0 : }
81 :
82 2088 : size_t pstring::hash::operator() (const pstring& val) const
83 : {
84 : // TODO: make this hashing algoritm more efficient.
85 2088 : size_t hash_val = val.size();
86 4176 : size_t loop_size = ::std::min<size_t>(hash_val, 20); // prevent too much looping.
87 : const char* p = val.get();
88 19256 : for (size_t i = 0; i < loop_size; ++i, ++p)
89 : {
90 17168 : hash_val += static_cast<size_t>(*p);
91 17168 : hash_val *= 2;
92 : }
93 :
94 2088 : return hash_val;
95 : }
96 :
97 16 : bool pstring::operator== (const pstring& r) const
98 : {
99 16 : if (m_size != r.m_size)
100 : // lengths differ.
101 : return false;
102 :
103 16 : const char* pos1 = m_pos;
104 16 : const char* pos2 = r.m_pos;
105 32 : for (size_t i = 0; i < m_size; ++i, ++pos1, ++pos2)
106 32 : if (*pos1 != *pos2)
107 : return false;
108 :
109 : return true;
110 : }
111 :
112 0 : bool pstring::operator< (const pstring& r) const
113 : {
114 0 : size_t n = std::min(m_size, r.m_size);
115 0 : const char* p1 = m_pos;
116 0 : const char* p2 = r.m_pos;
117 0 : for (size_t i = 0; i < n; ++i, ++p1, ++p2)
118 : {
119 0 : if (*p1 == *p2)
120 0 : continue;
121 :
122 0 : return *p1 < *p2;
123 : }
124 :
125 0 : return m_size < r.m_size;
126 : }
127 :
128 0 : bool pstring::operator== (const char* _str) const
129 : {
130 0 : size_t n = std::strlen(_str);
131 0 : if (n != m_size)
132 : // lengths differ.
133 : return false;
134 :
135 0 : if (!m_size)
136 : // both are empty strings.
137 : return true;
138 :
139 0 : return std::strncmp(_str, m_pos, n) == 0;
140 : }
141 :
142 0 : pstring pstring::trim() const
143 : {
144 0 : const char* p = m_pos;
145 0 : const char* p_end = p + m_size;
146 : // Find the first non-space character.
147 0 : for ( ;p != p_end; ++p)
148 : {
149 0 : switch (*p)
150 : {
151 : case ' ':
152 : case 0x0A:
153 : case 0x0D:
154 0 : continue;
155 : default:
156 : ;
157 : }
158 : break;
159 : }
160 :
161 0 : if (p == p_end)
162 : {
163 : // This string is empty.
164 : return pstring();
165 : }
166 :
167 : // Find the last non-space character.
168 0 : for (--p_end; p_end != p; --p_end)
169 : {
170 0 : switch (*p_end)
171 : {
172 : case ' ':
173 : case 0x0A:
174 : case 0x0D:
175 0 : continue;
176 : default:
177 : ;
178 : }
179 : break;
180 : }
181 :
182 0 : ++p_end;
183 0 : return pstring(p, p_end-p);
184 : }
185 :
186 0 : pstring pstring::intern() const
187 : {
188 0 : return intern(m_pos, m_size);
189 : }
190 :
191 4200 : }
|