[Libreoffice-commits] core.git: include/o3tl sw/source
Noel Grandin (via logerrit)
logerrit at kemper.freedesktop.org
Tue Aug 31 12:27:23 UTC 2021
include/o3tl/hash_combine.hxx | 22 ++++++++++
sw/source/core/inc/fntcache.hxx | 35 ++++++++++++++--
sw/source/core/txtnode/fntcache.cxx | 77 +++++++++++-------------------------
3 files changed, 77 insertions(+), 57 deletions(-)
New commits:
commit bb5425ed3d8cc04e4242059a17912752d6b48c53
Author: Noel Grandin <noel at peralex.com>
AuthorDate: Sat Aug 28 18:53:07 2021 +0200
Commit: Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Tue Aug 31 14:26:46 2021 +0200
tdf#135683 speed up writer layout cache access
can be hot, so use a std::unordered_map
Change-Id: I70e34e80cad67536414c71facbe0222dd88c65a7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121208
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
diff --git a/include/o3tl/hash_combine.hxx b/include/o3tl/hash_combine.hxx
index 139ee981699c..f56beda62672 100644
--- a/include/o3tl/hash_combine.hxx
+++ b/include/o3tl/hash_combine.hxx
@@ -11,6 +11,17 @@
namespace o3tl
{
+template <typename T, typename N>
+inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const* pValue, size_t nCount)
+{
+ static_assert(sizeof(nSeed) == 4);
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ nSeed ^= std::hash<T>{}(*pValue) + 0x9E3779B9u + (nSeed << 6) + (nSeed >> 2);
+ ++pValue;
+ }
+}
+
template <typename T, typename N>
inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const& nValue)
{
@@ -18,6 +29,17 @@ inline std::enable_if_t<(sizeof(N) == 4)> hash_combine(N& nSeed, T const& nValue
nSeed ^= std::hash<T>{}(nValue) + 0x9E3779B9u + (nSeed << 6) + (nSeed >> 2);
}
+template <typename T, typename N>
+inline std::enable_if_t<(sizeof(N) == 8)> hash_combine(N& nSeed, T const* pValue, size_t nCount)
+{
+ static_assert(sizeof(nSeed) == 8);
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ nSeed ^= std::hash<T>{}(*pValue) + 0x9E3779B97F4A7C15llu + (nSeed << 12) + (nSeed >> 4);
+ ++pValue;
+ }
+}
+
template <typename T, typename N>
inline std::enable_if_t<(sizeof(N) == 8)> hash_combine(N& nSeed, T const& nValue)
{
diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx
index ab5c6a9e473b..0bdc4757d9b3 100644
--- a/sw/source/core/inc/fntcache.hxx
+++ b/sw/source/core/inc/fntcache.hxx
@@ -23,7 +23,7 @@
#include <sal/config.h>
#include <cstdint>
-#include <map>
+#include <unordered_map>
#include <vcl/font.hxx>
#include <vcl/vclptr.hxx>
@@ -60,9 +60,34 @@ void SwClearFntCacheTextGlyphs();
extern SwFntCache *pFntCache;
extern SwFntObj *pLastFont;
-struct SwTextGlyphsKey;
-bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r);
-struct SwTextGlyphsData;
+/**
+ * Defines a substring on a given output device, to be used as an std::unordered_map<>
+ * key.
+ */
+struct SwTextGlyphsKey
+{
+ VclPtr<OutputDevice> m_pOutputDevice;
+ OUString m_aText;
+ sal_Int32 m_nIndex;
+ sal_Int32 m_nLength;
+ size_t mnHashCode;
+
+ SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength);
+ bool operator==(SwTextGlyphsKey const & rhs) const;
+};
+struct SwTextGlyphsKeyHash
+{
+ size_t operator()(SwTextGlyphsKey const & rKey) const { return rKey.mnHashCode; }
+};
+/**
+ * Glyphs and text width for the given SwTextGlyphsKey.
+ */
+struct SwTextGlyphsData
+{
+ SalLayoutGlyphs m_aTextGlyphs;
+ tools::Long m_nTextWidth = -1; // -1 = not computed yet
+};
+typedef std::unordered_map<SwTextGlyphsKey, SwTextGlyphsData, SwTextGlyphsKeyHash> SwTextGlyphsMap;
class SwFntObj final : public SwCacheObj
{
@@ -86,7 +111,7 @@ class SwFntObj final : public SwCacheObj
bool m_bPaintBlank : 1;
/// Cache of already calculated layout glyphs and text widths.
- std::map<SwTextGlyphsKey, SwTextGlyphsData> m_aTextGlyphs;
+ SwTextGlyphsMap m_aTextGlyphs;
static tools::Long s_nPixWidth;
static MapMode *s_pPixMap;
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index 9490fe51add0..17be5c9f0eef 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -57,6 +57,7 @@
#include <strings.hrc>
#include <fntcap.hxx>
#include <vcl/outdev/ScopedStates.hxx>
+#include <o3tl/hash_combine.hxx>
using namespace ::com::sun::star;
@@ -73,26 +74,31 @@ MapMode* SwFntObj::s_pPixMap = nullptr;
static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > s_pFntObjPixOut {};
/**
- * Defines a substring on a given output device, to be used as an std::map<>
+ * Defines a substring on a given output device, to be used as an std::unordered_map<>
* key.
*/
-struct SwTextGlyphsKey
+SwTextGlyphsKey::SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength)
+ : m_pOutputDevice(pOutputDevice), m_aText(sText), m_nIndex(nIndex), m_nLength(nLength)
{
- VclPtr<OutputDevice> m_pOutputDevice;
- OUString m_aText;
- sal_Int32 m_nIndex;
- sal_Int32 m_nLength;
-
-};
-
-/**
- * Glyphs and text width for the given SwTextGlyphsKey.
- */
-struct SwTextGlyphsData
+ mnHashCode = 0;
+ o3tl::hash_combine(mnHashCode, pOutputDevice.get());
+ o3tl::hash_combine(mnHashCode, m_nIndex);
+ o3tl::hash_combine(mnHashCode, m_nLength);
+ if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= m_aText.getLength())
+ o3tl::hash_combine(mnHashCode, m_aText.getStr() + m_nIndex, m_nLength);
+}
+bool SwTextGlyphsKey::operator==(SwTextGlyphsKey const & rhs) const
{
- SalLayoutGlyphs m_aTextGlyphs;
- tools::Long m_nTextWidth = -1; // -1 = not computed yet
-};
+ bool b = m_pOutputDevice.get() == rhs.m_pOutputDevice.get()
+ && m_nIndex == rhs.m_nIndex
+ && m_nLength == rhs.m_nLength;
+ if (!b)
+ return false;
+ if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= m_aText.getLength())
+ return m_aText.subView(m_nIndex,m_nLength) == rhs.m_aText.subView(m_nIndex, m_nLength);
+ return m_aText == rhs.m_aText;
+}
+
namespace
{
@@ -118,39 +124,6 @@ tools::Long EvalGridWidthAdd( const SwTextGridItem *const pGrid, const SwDrawTex
}
-bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r)
-{
- if (l.m_pOutputDevice.get() < r.m_pOutputDevice.get())
- return true;
- if (l.m_pOutputDevice.get() > r.m_pOutputDevice.get())
- return false;
- if (l.m_nIndex < r.m_nIndex)
- return true;
- if (l.m_nIndex > r.m_nIndex)
- return false;
- if (l.m_nLength < r.m_nLength)
- return true;
- if (l.m_nLength > r.m_nLength)
- return false;
-
- // Comparing strings is expensive, so compare them:
- // - only at the end of this function
- // - only once
- // - only the relevant substring (if the index/length is not out of bounds)
- sal_Int32 nRet = 0;
- if (l.m_nLength < 0 || l.m_nIndex < 0 || l.m_nIndex + l.m_nLength > l.m_aText.getLength())
- nRet = l.m_aText.compareTo(r.m_aText);
- else
- nRet = memcmp(l.m_aText.getStr() + l.m_nIndex, r.m_aText.getStr() + r.m_nIndex,
- l.m_nLength * sizeof(sal_Unicode));
- if (nRet < 0)
- return true;
- if (nRet > 0)
- return false;
-
- return false;
-};
-
void SwFntCache::Flush( )
{
if ( pLastFont )
@@ -220,7 +193,7 @@ void SwFntObj::CreatePrtFont( const OutputDevice& rPrt )
* Pre-calculates glyph items for the rendered subset of rKey's text, assuming
* outdev state does not change between the outdev calls.
*/
-static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it)
+static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, SwTextGlyphsMap::iterator it)
{
assert (!it->second.m_aTextGlyphs.IsValid());
@@ -243,7 +216,7 @@ static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, std::map<S
SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key)
{
- std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key);
+ SwTextGlyphsMap::iterator it = m_aTextGlyphs.find(key);
if(it != m_aTextGlyphs.end())
{
if( it->second.m_aTextGlyphs.IsValid())
@@ -259,7 +232,7 @@ SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key)
tools::Long SwFntObj::GetCachedTextWidth(const SwTextGlyphsKey& key, const vcl::text::TextLayoutCache* vclCache)
{
- std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = m_aTextGlyphs.find(key);
+ SwTextGlyphsMap::iterator it = m_aTextGlyphs.find(key);
if(it != m_aTextGlyphs.end() && it->second.m_nTextWidth >= 0)
return it->second.m_nTextWidth;
if(it == m_aTextGlyphs.end())
More information about the Libreoffice-commits
mailing list