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>
This commit is contained in:
@@ -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: */
|
||||
|
@@ -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())
|
||||
{
|
||||
|
@@ -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: */
|
||||
|
Reference in New Issue
Block a user