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
|
#pragma once
|
||||||
|
|
||||||
#include <sal/types.h>
|
#include <sal/types.h>
|
||||||
|
#include <rtl/ustring.hxx>
|
||||||
|
#include <o3tl/hash_combine.hxx>
|
||||||
|
|
||||||
#include <vcl/dllapi.h>
|
#include <vcl/dllapi.h>
|
||||||
|
|
||||||
@@ -48,6 +50,36 @@ public:
|
|||||||
std::vector<vcl::text::Run> runs;
|
std::vector<vcl::text::Run> runs;
|
||||||
TextLayoutCache(sal_Unicode const* pStr, sal_Int32 const nEnd);
|
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: */
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
||||||
|
@@ -154,40 +154,12 @@ namespace {
|
|||||||
return VerticalOrientation(nRet);
|
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
|
} // namespace
|
||||||
|
|
||||||
std::shared_ptr<const vcl::text::TextLayoutCache> GenericSalLayout::CreateTextLayoutCache(OUString const& rString)
|
std::shared_ptr<const vcl::text::TextLayoutCache> GenericSalLayout::CreateTextLayoutCache(OUString const& rString)
|
||||||
{
|
{
|
||||||
typedef o3tl::lru_map<OUString, std::shared_ptr<const vcl::text::TextLayoutCache>,
|
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 );
|
static vcl::DeleteOnDeinit< Cache > cache( 1000 );
|
||||||
if( Cache* map = cache.get())
|
if( Cache* map = cache.get())
|
||||||
{
|
{
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <vcl/glyphitemcache.hxx>
|
#include <vcl/glyphitemcache.hxx>
|
||||||
#include <vcl/vcllayout.hxx>
|
#include <vcl/vcllayout.hxx>
|
||||||
#include <tools/stream.hxx>
|
#include <tools/stream.hxx>
|
||||||
|
#include <TextLayoutCache.hxx>
|
||||||
|
|
||||||
SalLayoutGlyphs::SalLayoutGlyphs() {}
|
SalLayoutGlyphs::SalLayoutGlyphs() {}
|
||||||
|
|
||||||
@@ -146,7 +147,7 @@ SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const VclPtr<const Output
|
|||||||
SvMemoryStream stream;
|
SvMemoryStream stream;
|
||||||
WriteFont(stream, outputDevice->GetFont());
|
WriteFont(stream, outputDevice->GetFont());
|
||||||
o3tl::hash_combine(hashValue, static_cast<const char*>(stream.GetData()), stream.GetSize());
|
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, index);
|
||||||
o3tl::hash_combine(hashValue, len);
|
o3tl::hash_combine(hashValue, len);
|
||||||
o3tl::hash_combine(hashValue, logicPos.X());
|
o3tl::hash_combine(hashValue, logicPos.X());
|
||||||
@@ -158,7 +159,8 @@ inline bool SalLayoutGlyphsCache::CachedGlyphsKey::operator==(const CachedGlyphs
|
|||||||
{
|
{
|
||||||
return hashValue == other.hashValue && outputDevice == other.outputDevice
|
return hashValue == other.hashValue && outputDevice == other.outputDevice
|
||||||
&& index == other.index && len == other.len && logicPos == other.logicPos
|
&& 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: */
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||||
|
Reference in New Issue
Block a user