Partial fix for EXT-5071.

Changed the index on the keyword map in LLKeywords so that LLKeywords::findSegments() doesn't have to create LLWString objects to search the map.

Reviewed by Richard.
master
Monroe Linden 2010-02-17 18:18:18 -08:00
parent d742b3e911
commit 3e8320201f
2 changed files with 107 additions and 2 deletions

View File

@ -218,6 +218,86 @@ void LLKeywords::addToken(LLKeywordToken::TOKEN_TYPE type,
llassert(0);
}
}
LLKeywords::WStringMapIndex::WStringMapIndex(const WStringMapIndex& other)
{
if(other.mOwner)
{
copyData(other.mData, other.mLength);
}
else
{
mOwner = false;
mLength = other.mLength;
mData = other.mData;
}
}
LLKeywords::WStringMapIndex::WStringMapIndex(const LLWString& str)
{
copyData(str.data(), str.size());
}
LLKeywords::WStringMapIndex::WStringMapIndex(const llwchar *start, size_t length):
mData(start), mLength(length), mOwner(false)
{
}
LLKeywords::WStringMapIndex::~WStringMapIndex()
{
if(mOwner)
delete[] mData;
}
void LLKeywords::WStringMapIndex::copyData(const llwchar *start, size_t length)
{
llwchar *data = new llwchar[length];
memcpy((void*)data, (const void*)start, length * sizeof(llwchar));
mOwner = true;
mLength = length;
mData = data;
}
bool LLKeywords::WStringMapIndex::operator<(const LLKeywords::WStringMapIndex &other) const
{
// NOTE: Since this is only used to organize a std::map, it doesn't matter if it uses correct collate order or not.
// The comparison only needs to strictly order all possible strings, and be stable.
bool result = false;
const llwchar* self_iter = mData;
const llwchar* self_end = mData + mLength;
const llwchar* other_iter = other.mData;
const llwchar* other_end = other.mData + other.mLength;
while(true)
{
if(other_iter >= other_end)
{
// We've hit the end of other.
// This covers two cases: other being shorter than self, or the strings being equal.
// In either case, we want to return false.
result = false;
break;
}
else if(self_iter >= self_end)
{
// self is shorter than other.
result = true;
break;
}
else if(*self_iter != *other_iter)
{
// The current character differs. The strings are not equal.
result = *self_iter < *other_iter;
break;
}
self_iter++;
other_iter++;
}
return result;
}
LLColor3 LLKeywords::readColor( const std::string& s )
{
@ -429,7 +509,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 seg_len = p - cur;
if( seg_len > 0 )
{
LLWString word( cur, 0, seg_len );
WStringMapIndex word( cur, seg_len );
word_token_map_t::iterator map_iter = mWordTokenMap.find(word);
if( map_iter != mWordTokenMap.end() )
{

View File

@ -92,8 +92,33 @@ public:
const std::string& key,
const LLColor3& color,
const std::string& tool_tip = LLStringUtil::null);
// This class is here as a performance optimization.
// The word token map used to be defined as std::map<LLWString, LLKeywordToken*>.
// This worked, but caused a performance bottleneck due to memory allocation and string copies
// because it's not possible to search such a map without creating an LLWString.
// Using this class as the map index instead allows us to search using segments of an existing
// text run without copying them first, which greatly reduces overhead in LLKeywords::findSegments().
class WStringMapIndex
{
public:
// copy constructor
WStringMapIndex(const WStringMapIndex& other);
// constructor from a string (copies the string's data into the new object)
WStringMapIndex(const LLWString& str);
// constructor from pointer and length
// NOTE: does NOT copy data, caller must ensure that the lifetime of the pointer exceeds that of the new object!
WStringMapIndex(const llwchar *start, size_t length);
~WStringMapIndex();
bool operator<(const WStringMapIndex &other) const;
private:
void copyData(const llwchar *start, size_t length);
const llwchar *mData;
size_t mLength;
bool mOwner;
};
typedef std::map<LLWString, LLKeywordToken*> word_token_map_t;
typedef std::map<WStringMapIndex, LLKeywordToken*> word_token_map_t;
typedef word_token_map_t::const_iterator keyword_iterator_t;
keyword_iterator_t begin() const { return mWordTokenMap.begin(); }
keyword_iterator_t end() const { return mWordTokenMap.end(); }