diff options
-rw-r--r-- | indra/llui/llkeywords.cpp | 82 | ||||
-rw-r--r-- | indra/llui/llkeywords.h | 29 |
2 files changed, 108 insertions, 3 deletions
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index ede32084d0..75342afbe2 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -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() ) { diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 53377869ca..e5b66dfa56 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -92,8 +92,33 @@ public: const std::string& key, const LLColor3& color, const std::string& tool_tip = LLStringUtil::null); - - typedef std::map<LLWString, LLKeywordToken*> word_token_map_t; + + // 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<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(); } |