1 // string_table.cpp -- A shared string table for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "string_table.h"
22 #include "gnashconfig.h" // GNASH_STATS_STRING_TABLE_NOCASE
25 #include <boost/algorithm/string/case_conv.hpp>
27 //#define DEBUG_STRING_TABLE 1
28 //#define GNASH_STATS_STRING_TABLE_NOCASE 1
29 //#define GNASH_PARANOIA_LEVEL 3
31 #ifdef GNASH_STATS_STRING_TABLE_NOCASE
37 const std::string
string_table::_empty
;
40 string_table::find(const std::string
& t_f
, bool insert_unfound
)
42 if (t_f
.empty()) return 0;
44 table::index
<StringValue
>::type::iterator i
=
45 _table
.get
<StringValue
>().find(t_f
);
47 if (i
== _table
.get
<StringValue
>().end()) {
51 boost::mutex::scoped_lock
aLock(_lock
);
52 // Then we see if someone else managed to sneak past us.
53 i
= _table
.get
<StringValue
>().find(t_f
);
54 // If they did, use that value.
55 if (i
!= _table
.end()) return i
->id
;
57 return already_locked_insert(t_f
);
66 string_table::insert(const std::string
& to_insert
)
68 boost::mutex::scoped_lock
aLock(_lock
);
69 return already_locked_insert(to_insert
);
73 string_table::insert_group(const svt
* l
, std::size_t size
)
75 boost::mutex::scoped_lock
aLock(_lock
);
76 for (std::size_t i
= 0; i
< size
; ++i
) {
77 // Copy to avoid changing the original table.
80 // The keys don't have to be consecutive, so any time we find a key
81 // that is too big, jump a few keys to avoid rewriting this on every
83 if (s
.id
> _highestKey
) _highestKey
= s
.id
+ 256;
87 for (std::size_t i
= 0; i
< size
; ++i
) {
89 const std::string
& t
= boost::to_lower_copy(s
.value
);
91 _caseTable
[s
.id
] = already_locked_insert(t
);
94 #ifdef DEBUG_STRING_TABLE
95 std::cerr
<< "string_table group insert end -- size is " << _table
.size() << " _caseTable size is " << _caseTable
.size() << std::endl
;
102 string_table::already_locked_insert(const std::string
& to_insert
)
104 const key ret
= _table
.insert(svt(to_insert
, ++_highestKey
)).first
->id
;
106 #ifdef DEBUG_STRING_TABLE
107 int tscp
= 100; // table size checkpoint
108 size_t ts
= _table
.size();
109 if ( ! (ts
% tscp
) ) { std::cerr
<< "string_table size grew to " << ts
<< std::endl
; }
112 const std::string lower
= boost::to_lower_copy(to_insert
);
114 // Insert the caseless equivalent if it's not there. We're locked for
115 // the whole of this function, so we can do what we like.
116 if (lower
!= to_insert
) {
118 // Find the caseless value in the table
119 table::index
<StringValue
>::type::iterator it
=
120 _table
.get
<StringValue
>().find(lower
);
122 const key nocase
= (it
== _table
.end()) ?
123 _table
.insert(svt(lower
, ++_highestKey
)).first
->id
: it
->id
;
125 #ifdef DEBUG_STRING_TABLE
127 if ( ! (ts
% tscp
) ) { std::cerr
<< "string_table size grew to " << ts
<< std::endl
; }
128 #endif // DEBUG_STRING_TABLE
130 _caseTable
[ret
] = nocase
;
138 string_table::setHighestKnownLowercase(key k
)
140 _highestKnownLowercase
= k
;
144 string_table::noCase(key a
) const
146 #ifdef GNASH_STATS_STRING_TABLE_NOCASE
147 static stats::KeyLookup
kcl("string_table::noCase(maplookups)", *this);
148 #endif // GNASH_STATS_STRING_TABLE_NOCASE
150 // Avoid checking keys known to be lowercase
151 if ( a
<= _highestKnownLowercase
) {
152 #if GNASH_PARANOIA_LEVEL > 2
153 assert(_caseTable
.find(a
) == _caseTable
.end());
158 // MOVE this block around for special needs
159 #ifdef GNASH_STATS_STRING_TABLE_NOCASE
163 // TODO: an even/odd based rule to tell what's lowercase already
164 // would speed things up even for unknown
167 std::map
<key
, key
>::const_iterator i
= _caseTable
.find(a
);
168 if ( i
!= _caseTable
.end() ) return i
->second
;
174 equal(string_table
& st
, string_table::key a
, string_table::key b
,
177 if (a
== b
) return true;
178 return caseless
&& (st
.noCase(a
) == st
.noCase(b
));