sc/inc/column.hxx                          |    2 -
 sc/inc/interpretercontext.hxx              |   40 +++++++++++++++---------
 sc/inc/patattr.hxx                         |    2 +
 sc/source/core/data/patattr.cxx            |   11 ++++++
 sc/source/core/tool/interpretercontext.cxx |   47 ++++++++++++++++++++++-------
 5 files changed, 75 insertions(+), 27 deletions(-)

New commits:
commit 8f70b99b4dd162df7a6a124ccd53f3814ff10b00
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Fri Mar 1 11:23:59 2024 +0000
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Sat Mar 2 21:54:47 2024 +0100

    if the formatter was to change, then the cache should be dropped
    
    Change-Id: I98edea680f5300c4375168391627ac654ea3779c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164228
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sc/source/core/tool/interpretercontext.cxx 
b/sc/source/core/tool/interpretercontext.cxx
index 03d5036b6e63..ef9e1f3947bf 100644
--- a/sc/source/core/tool/interpretercontext.cxx
+++ b/sc/source/core/tool/interpretercontext.cxx
@@ -58,11 +58,17 @@ void ScInterpreterContext::SetDocAndFormatter(const 
ScDocument& rDoc, SvNumberFo
         mxScLookupCache.reset();
         mpDoc = &rDoc;
     }
-    mpFormatter = pFormatter;
+    if (mpFormatter != pFormatter)
+    {
+        maNFBuiltInCache.clear();
+        maNFTypeCache.clear();
+        mpFormatter = pFormatter;
+    }
 }
 
 void ScInterpreterContext::initFormatTable()
 {
+    assert(!mpFormatter && maNFBuiltInCache.empty() && maNFTypeCache.empty());
     mpFormatter = mpDoc->GetFormatTable(); // will assert if not main thread
 }
 
commit 2c3605405225de4b850064cf25b15cd64be1409b
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Thu Feb 29 20:09:09 2024 +0000
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Sat Mar 2 21:54:34 2024 +0100

    avoid SvNumberFormatter lock in formula-group-threading
    
    keep a per-interpret-thread cache of the SvNumberFormatter
    mapping while formula-group-threading, this is similar to:
    
    commit c2d8341ee392949274b901abfd44d9645d2e4e36
    Date:   Tue Oct 15 08:32:22 2019 +0530
    
        Cache last used number-format-type in interpreter-context
    
    Change-Id: Ie99807eaf2f3260cec357f9d66307df0a69826e9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164227
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 306d7d28de3f..0aa812f038a2 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -986,7 +986,7 @@ inline const SfxPoolItem& ScColumnData::GetAttr( SCROW 
nRow, sal_uInt16 nWhich,
 
 inline sal_uInt32 ScColumnData::GetNumberFormat( const ScInterpreterContext& 
rContext, SCROW nRow ) const
 {
-    return pAttrArray->GetPattern( nRow )->GetNumberFormat( 
rContext.GetFormatTable() );
+    return pAttrArray->GetPattern( nRow )->GetNumberFormat( rContext );
 }
 
 inline void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, 
sal_uInt32 nIndex )
diff --git a/sc/inc/interpretercontext.hxx b/sc/inc/interpretercontext.hxx
index 39d528cb6ca9..c46f00395cc0 100644
--- a/sc/inc/interpretercontext.hxx
+++ b/sc/inc/interpretercontext.hxx
@@ -11,6 +11,8 @@
 
 #include <vector>
 #include <memory>
+#include <i18nlangtag/lang.h>
+#include <o3tl/sorted_vector.hxx>
 #include "types.hxx"
 
 namespace formula
@@ -34,20 +36,6 @@ struct DelayedSetNumberFormat
     sal_uInt32 mnNumberFormat;
 };
 
-struct NFIndexAndFmtType
-{
-    sal_uInt32 nIndex;
-    SvNumFormatType eType : 16;
-    bool bIsValid : 1;
-
-    NFIndexAndFmtType()
-        : nIndex(0)
-        , eType(static_cast<SvNumFormatType>(0))
-        , bIsValid(false)
-    {
-    }
-};
-
 class ScInterpreterContextPool;
 
 struct ScInterpreterContext
@@ -77,6 +65,8 @@ struct ScInterpreterContext
 
     SvNumFormatType GetNumberFormatType(sal_uInt32 nFIndex) const;
 
+    sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType 
eLnge) const;
+
 private:
     friend class ScInterpreterContextPool;
     void ResetTokens();
@@ -85,7 +75,27 @@ private:
     void ClearLookupCache(const ScDocument* pDoc);
     void initFormatTable();
     SvNumberFormatter* mpFormatter;
-    mutable NFIndexAndFmtType maNFTypeCache;
+
+    template <typename T> struct CompareKey
+    {
+        bool operator()(const T& lhs, const T& rhs) const { return lhs.nKey < 
rhs.nKey; }
+    };
+
+    struct NFType
+    {
+        sal_uInt32 nKey;
+        mutable SvNumFormatType eType;
+    };
+    // map from format index to type
+    mutable o3tl::sorted_vector<NFType, CompareKey<NFType>> maNFTypeCache;
+
+    struct NFBuiltIn
+    {
+        sal_uInt64 nKey;
+        mutable sal_uInt32 nFormat;
+    };
+    // map from format+lang to builtin format
+    mutable o3tl::sorted_vector<NFBuiltIn, CompareKey<NFBuiltIn>> 
maNFBuiltInCache;
 };
 
 class ScThreadedInterpreterContextGetterGuard;
diff --git a/sc/inc/patattr.hxx b/sc/inc/patattr.hxx
index 3c790c7637e3..bbb55b5a309f 100644
--- a/sc/inc/patattr.hxx
+++ b/sc/inc/patattr.hxx
@@ -32,6 +32,7 @@
 
 namespace vcl { class Font; }
 namespace model { class ComplexColor; }
+struct ScInterpreterContext;
 class OutputDevice;
 class Fraction;
 class ScStyleSheet;
@@ -237,6 +238,7 @@ public:
     bool                    IsSymbolFont() const;
 
     sal_uInt32              GetNumberFormat( SvNumberFormatter* ) const;
+    sal_uInt32              GetNumberFormat( const ScInterpreterContext& 
rContext ) const;
     sal_uInt32              GetNumberFormat( SvNumberFormatter* pFormatter,
                                              const SfxItemSet* pCondSet ) 
const;
 
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index 59f9fa1866b4..95823cee9473 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -1652,6 +1652,17 @@ sal_uInt32 ScPatternAttr::GetNumberFormat( 
SvNumberFormatter* pFormatter ) const
     return nFormat;
 }
 
+sal_uInt32 ScPatternAttr::GetNumberFormat( const ScInterpreterContext& 
rContext ) const
+{
+    sal_uInt32 nFormat = getNumberFormatKey(GetItemSet());
+    LanguageType eLang = getLanguageType(GetItemSet());
+    if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
+        ;       // it remains as it is
+    else
+        nFormat = rContext.GetFormatForLanguageIfBuiltIn( nFormat, eLang );
+    return nFormat;
+}
+
 // the same if conditional formatting is in play:
 
 sal_uInt32 ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter,
diff --git a/sc/source/core/tool/interpretercontext.cxx 
b/sc/source/core/tool/interpretercontext.cxx
index deb6f6d0ed5b..03d5036b6e63 100644
--- a/sc/source/core/tool/interpretercontext.cxx
+++ b/sc/source/core/tool/interpretercontext.cxx
@@ -83,19 +83,38 @@ void ScInterpreterContext::ClearLookupCache(const 
ScDocument* pDoc)
 SvNumFormatType ScInterpreterContext::GetNumberFormatType(sal_uInt32 nFIndex) 
const
 {
     if (!mpDoc->IsThreadedGroupCalcInProgress())
-    {
         return mpFormatter->GetType(nFIndex);
-    }
 
-    if (maNFTypeCache.bIsValid && maNFTypeCache.nIndex == nFIndex)
-    {
-        return maNFTypeCache.eType;
-    }
+    // Search/update cache by attempting to find nFIndex by inserting a new 
entry
+    auto result = maNFTypeCache.insert(NFType{ nFIndex, SvNumFormatType::ALL 
});
+    if (!result.second) // already exists, so return that SvNumFormatType
+        return result.first->eType;
 
-    maNFTypeCache.nIndex = nFIndex;
-    maNFTypeCache.eType = mpFormatter->GetType(nFIndex);
-    maNFTypeCache.bIsValid = true;
-    return maNFTypeCache.eType;
+    // Didn't exist, overwrite the placeholder SvNumFormatType::ALL with the 
real type
+    SvNumFormatType eType = mpFormatter->GetType(nFIndex);
+    result.first->eType = eType;
+    return eType;
+}
+
+sal_uInt32 ScInterpreterContext::GetFormatForLanguageIfBuiltIn(sal_uInt32 
nFormat,
+                                                               LanguageType 
eLnge) const
+{
+    if (!mpFormatter)
+        return nFormat;
+
+    if (!mpDoc->IsThreadedGroupCalcInProgress())
+        return mpFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLnge);
+
+    sal_uInt64 nKey = (static_cast<sal_uInt64>(nFormat) << 32) | eLnge.get();
+    // Search/update cache by attempting to find nFormat+eLnge by inserting a 
new entry
+    auto result = maNFBuiltInCache.insert(NFBuiltIn{ nKey, 0 });
+    if (!result.second) // already exists, so return that dest Format
+        return result.first->nFormat;
+
+    // Didn't exist, overwrite the placeholder zero with the real format
+    nFormat = mpFormatter->GetFormatForLanguageIfBuiltIn(nFormat, eLnge);
+    result.first->nFormat = nFormat;
+    return nFormat;
 }
 
 /* ScInterpreterContextPool */

Reply via email to