diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2022-04-06 19:28:07 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2022-04-08 21:28:15 +0200 |
commit | 94c2fb28d76c9c37849412a66b31d6861bce3155 (patch) | |
tree | a29aae0728d3ee744cf02ee5cc3a831154b092c2 | |
parent | 1b593dbc62dc2ceebc3f8be30d7221c916098f6d (diff) |
faster hashing of very long strings in SalLayoutGlyphsCache
tdf#147284 being a (pathological) testcase.
Change-Id: I08d8dffb40193b461555bed818c040761e8d575b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132669
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r-- | vcl/inc/TextLayoutCache.hxx | 32 | ||||
-rw-r--r-- | vcl/source/gdi/CommonSalLayout.cxx | 30 | ||||
-rw-r--r-- | vcl/source/gdi/impglyphitem.cxx | 6 |
3 files changed, 37 insertions, 31 deletions
diff --git a/vcl/inc/TextLayoutCache.hxx b/vcl/inc/TextLayoutCache.hxx index 0ce0c19d8278..ecb85ea7043d 100644 --- a/vcl/inc/TextLayoutCache.hxx +++ b/vcl/inc/TextLayoutCache.hxx @@ -20,6 +20,8 @@ #pragma once #include <sal/types.h> +#include <rtl/ustring.hxx> +#include <o3tl/hash_combine.hxx> #include <vcl/dllapi.h> @@ -48,6 +50,36 @@ public: std::vector<vcl::text::Run> runs; TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd); }; + +struct FirstCharsStringHash +{ + size_t operator()(const OUString& str) const + { + // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, + // and computing an entire hash could almost negate the gain of hashing. Hash just first + // characters, that should be good enough. + size_t hash + = rtl_ustr_hashCode_WithLength(str.getStr(), std::min<size_t>(100, str.getLength())); + o3tl::hash_combine(hash, str.getLength()); + return hash; + } +}; + +struct FastStringCompareEqual +{ + bool operator()(const OUString& str1, const OUString& str2) const + { + // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, + // and OUString operator == compares backwards and using hard-written code, while + // memcmp() compares much faster. + if (str1.getLength() != str2.getLength()) + return false; + if (str1.getStr() == str2.getStr()) + return true; + return memcmp(str1.getStr(), str2.getStr(), str1.getLength() * sizeof(str1.getStr()[0])) + == 0; + } +}; } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 8dee28727997..2c8a4db8398f 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -154,40 +154,12 @@ namespace { return VerticalOrientation(nRet); } -struct FirstCharsStringHash -{ - size_t operator()( const OUString& str ) const - { - // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, - // and computing an entire hash could almost negate the gain of hashing. Hash just first - // characters, that should be good enough. - size_t hash = rtl_ustr_hashCode_WithLength( str.getStr(), std::min<size_t>( 100, str.getLength())); - o3tl::hash_combine(hash, str.getLength()); - return hash; - } -}; - -struct ForwardStringCompareEqual -{ - bool operator()( const OUString& str1, const OUString& str2 ) const - { - // Strings passed to GenericSalLayout::CreateTextLayoutCache() may be very long, - // and OUString operator == compares backwards, which is inefficient for very long - // strings (bad memory prefetch). - if( str1.getLength() != str2.getLength()) - return false; - if( str1.getStr() == str2.getStr()) - return true; - return memcmp( str1.getStr(), str2.getStr(), str1.getLength() * sizeof( str1.getStr()[ 0 ] )) == 0; - } -}; - } // namespace std::shared_ptr<const vcl::text::TextLayoutCache> GenericSalLayout::CreateTextLayoutCache(OUString const& rString) { typedef o3tl::lru_map<OUString, std::shared_ptr<const vcl::text::TextLayoutCache>, - FirstCharsStringHash, ForwardStringCompareEqual> Cache; + vcl::text::FirstCharsStringHash, vcl::text::FastStringCompareEqual> Cache; static vcl::DeleteOnDeinit< Cache > cache( 1000 ); if( Cache* map = cache.get()) { diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index eaf8cf5c8453..d320d27dad88 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -21,6 +21,7 @@ #include <vcl/glyphitemcache.hxx> #include <vcl/vcllayout.hxx> #include <tools/stream.hxx> +#include <TextLayoutCache.hxx> SalLayoutGlyphs::SalLayoutGlyphs() {} @@ -146,7 +147,7 @@ SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const VclPtr<const Output SvMemoryStream stream; WriteFont(stream, outputDevice->GetFont()); o3tl::hash_combine(hashValue, static_cast<const char*>(stream.GetData()), stream.GetSize()); - o3tl::hash_combine(hashValue, text); + o3tl::hash_combine(hashValue, vcl::text::FirstCharsStringHash()(text)); o3tl::hash_combine(hashValue, index); o3tl::hash_combine(hashValue, len); o3tl::hash_combine(hashValue, logicPos.X()); @@ -158,7 +159,8 @@ inline bool SalLayoutGlyphsCache::CachedGlyphsKey::operator==(const CachedGlyphs { return hashValue == other.hashValue && outputDevice == other.outputDevice && index == other.index && len == other.len && logicPos == other.logicPos - && logicWidth == other.logicWidth && text == other.text; + && logicWidth == other.logicWidth + && vcl::text::FastStringCompareEqual()(text, other.text); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |