[Libreoffice-commits] core.git: 20 commits - editeng/source include/editeng include/svl sc/inc sc/qa sc/source svl/Library_svl.mk svl/qa svl/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Oct 4 16:15:12 PDT 2013


 editeng/source/editeng/editobj.cxx     |   79 +++++
 editeng/source/editeng/editobj2.hxx    |   14 
 include/editeng/editobj.hxx            |   16 +
 include/svl/sharedstringpool.hxx       |   94 ++++++
 sc/inc/column.hxx                      |    3 
 sc/inc/document.hxx                    |   10 
 sc/inc/formulagroup.hxx                |    7 
 sc/inc/queryentry.hxx                  |    3 
 sc/inc/table.hxx                       |    3 
 sc/qa/unit/ucalc.cxx                   |  132 +++++++++
 sc/qa/unit/ucalc.hxx                   |    2 
 sc/source/core/data/column2.cxx        |    8 
 sc/source/core/data/column3.cxx        |  111 +++++--
 sc/source/core/data/documen2.cxx       |   17 +
 sc/source/core/data/document.cxx       |   16 +
 sc/source/core/data/documentimport.cxx |    9 
 sc/source/core/data/table2.cxx         |   16 +
 sc/source/core/inc/interpre.hxx        |    2 
 sc/source/core/tool/formulagroup.cxx   |   17 -
 sc/source/core/tool/interpr1.cxx       |  475 ++++++++++++++++++---------------
 sc/source/core/tool/interpr2.cxx       |    4 
 sc/source/core/tool/interpr4.cxx       |    8 
 sc/source/core/tool/queryentry.cxx     |    2 
 svl/Library_svl.mk                     |    1 
 svl/qa/unit/svl.cxx                    |  113 +++++++
 svl/source/misc/sharedstringpool.cxx   |  145 ++++++++++
 26 files changed, 1023 insertions(+), 284 deletions(-)

New commits:
commit 3ff650d5659ed050e33074355ee2384f1569b21e
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 4 19:13:26 2013 -0400

    Rename StringPool to SharedStringPool because that's what it is.
    
    Change-Id: I2fc3ce4f0c2291d402cb470346d5561373fb51e7

diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index 4e6af47..3a5d41c 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -44,7 +44,7 @@
 
 #include <vcl/graph.hxx>
 #include <svl/intitem.hxx>
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 #include <unotools/fontcvt.hxx>
 #include <tools/tenccvt.hxx>
 
@@ -149,17 +149,17 @@ ContentInfo::~ContentInfo()
     aAttribs.clear();
 }
 
-void ContentInfo::NormalizeString( svl::StringPool& rPool )
+void ContentInfo::NormalizeString( svl::SharedStringPool& rPool )
 {
     aText = OUString(rPool.intern(aText));
 }
 
-sal_uIntPtr ContentInfo::GetStringID( const svl::StringPool& rPool ) const
+sal_uIntPtr ContentInfo::GetStringID( const svl::SharedStringPool& rPool ) const
 {
     return rPool.getIdentifier(aText);
 }
 
-sal_uIntPtr ContentInfo::GetStringIDIgnoreCase( const svl::StringPool& rPool ) const
+sal_uIntPtr ContentInfo::GetStringIDIgnoreCase( const svl::SharedStringPool& rPool ) const
 {
     return rPool.getIdentifierIgnoreCase(aText);
 }
@@ -332,17 +332,17 @@ editeng::FieldUpdater EditTextObject::GetFieldUpdater()
     return mpImpl->GetFieldUpdater();
 }
 
-void EditTextObject::NormalizeString( svl::StringPool& rPool )
+void EditTextObject::NormalizeString( svl::SharedStringPool& rPool )
 {
     mpImpl->NormalizeString(rPool);
 }
 
-bool EditTextObject::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+bool EditTextObject::GetStringIDs( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
 {
     return mpImpl->GetStringIDs(rPool, rIDs);
 }
 
-bool EditTextObject::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+bool EditTextObject::GetStringIDsIgnoreCase( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
 {
     return mpImpl->GetStringIDsIgnoreCase(rPool, rIDs);
 }
@@ -633,7 +633,7 @@ void EditTextObjectImpl::SetUserType( sal_uInt16 n )
     nUserType = n;
 }
 
-void EditTextObjectImpl::NormalizeString( svl::StringPool& rPool )
+void EditTextObjectImpl::NormalizeString( svl::SharedStringPool& rPool )
 {
     ContentInfosType::iterator it = aContents.begin(), itEnd = aContents.end();
     for (; it != itEnd; ++it)
@@ -643,7 +643,7 @@ void EditTextObjectImpl::NormalizeString( svl::StringPool& rPool )
     }
 }
 
-bool EditTextObjectImpl::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+bool EditTextObjectImpl::GetStringIDs( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
 {
     std::vector<sal_uIntPtr> aIDs;
     aIDs.reserve(aContents.size());
@@ -662,7 +662,7 @@ bool EditTextObjectImpl::GetStringIDs( const svl::StringPool& rPool, std::vector
     return true;
 }
 
-bool EditTextObjectImpl::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+bool EditTextObjectImpl::GetStringIDsIgnoreCase( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
 {
     std::vector<sal_uIntPtr> aIDs;
     aIDs.reserve(aContents.size());
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index d2118d7..20dafe9 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -37,7 +37,7 @@ struct Section;
 
 namespace svl {
 
-class StringPool;
+class SharedStringPool;
 
 }
 
@@ -142,9 +142,9 @@ private:
 public:
                         ~ContentInfo();
 
-    void NormalizeString( svl::StringPool& rPool );
-    sal_uIntPtr GetStringID( const svl::StringPool& rPool ) const;
-    sal_uIntPtr GetStringIDIgnoreCase( const svl::StringPool& rPool ) const;
+    void NormalizeString( svl::SharedStringPool& rPool );
+    sal_uIntPtr GetStringID( const svl::SharedStringPool& rPool ) const;
+    sal_uIntPtr GetStringIDIgnoreCase( const svl::SharedStringPool& rPool ) const;
 
     const XEditAttributesType& GetAttribs() const { return aAttribs; }
     XEditAttributesType& GetAttribs() { return aAttribs; }
@@ -208,9 +208,9 @@ public:
     sal_uInt16 GetUserType() const;
     void SetUserType( sal_uInt16 n );
 
-    void NormalizeString( svl::StringPool& rPool );
-    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
-    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    void NormalizeString( svl::SharedStringPool& rPool );
+    bool GetStringIDs( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
 
     bool                    IsVertical() const;
     void                    SetVertical( bool b );
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index 4751469..3d1ccca 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -51,7 +51,7 @@ struct Section;
 
 namespace svl {
 
-class StringPool;
+class SharedStringPool;
 
 }
 
@@ -83,10 +83,10 @@ public:
      *
      * @param rPool shared string pool.
      */
-    void NormalizeString( svl::StringPool& rPool );
+    void NormalizeString( svl::SharedStringPool& rPool );
 
-    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
-    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDs( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::SharedStringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
 
     const SfxItemPool* GetPool() const;
     sal_uInt16 GetUserType() const;    // For OutlinerMode, it can however not save in compatible format
diff --git a/include/svl/stringpool.hxx b/include/svl/sharedstringpool.hxx
similarity index 95%
rename from include/svl/stringpool.hxx
rename to include/svl/sharedstringpool.hxx
index fbcff1e..6793162 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/sharedstringpool.hxx
@@ -25,7 +25,7 @@ namespace svl {
  * original-cased strings to upper-cased strings for case insensitive
  * operations.
  */
-class SVL_DLLPUBLIC StringPool
+class SVL_DLLPUBLIC SharedStringPool
 {
     typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
     typedef std::pair<StrHashType::iterator, bool> InsertResultType;
@@ -38,8 +38,8 @@ class SVL_DLLPUBLIC StringPool
 
 public:
 
-    StringPool();
-    StringPool( const CharClass* pCharClass );
+    SharedStringPool();
+    SharedStringPool( const CharClass* pCharClass );
 
     /**
      * Intern a string object into the shared string pool.
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 2ef6073..550f7b7 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -50,7 +50,7 @@
 
 namespace editeng { class SvxBorderLine; }
 namespace formula { struct VectorRefArray; }
-namespace svl { class StringPool; }
+namespace svl { class SharedStringPool; }
 
 namespace sc {
     struct FormulaGroupContext;
@@ -245,7 +245,7 @@ private:
 
     rtl::Reference<ScPoolHelper> xPoolHelper;
 
-    boost::scoped_ptr<svl::StringPool> mpCellStringPool;
+    boost::scoped_ptr<svl::SharedStringPool> mpCellStringPool;
 
     SfxUndoManager*     mpUndoManager;
     ScFieldEditEngine*  pEditEngine;                    // uses pEditPool from xPoolHelper
@@ -859,8 +859,8 @@ public:
      */
     double* GetValueCell( const ScAddress& rPos );
 
-    svl::StringPool& GetCellStringPool();
-    const svl::StringPool& GetCellStringPool() const;
+    svl::SharedStringPool& GetCellStringPool();
+    const svl::SharedStringPool& GetCellStringPool() const;
     sal_uIntPtr GetCellStringID( const ScAddress& rPos ) const;
     sal_uIntPtr GetCellStringIDIgnoreCase( const ScAddress& rPos ) const;
 
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index a8d20bb..fc3af2a 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -14,7 +14,7 @@
 #include "types.hxx"
 #include "platforminfo.hxx"
 
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 
 #include <vector>
 #include <boost/noncopyable.hpp>
@@ -33,7 +33,7 @@ struct FormulaGroupContext : boost::noncopyable
     typedef boost::ptr_vector<NumArrayType> NumArrayStoreType;
     typedef boost::ptr_vector<StrArrayType> StrArrayStoreType;
 
-    svl::StringPool maStrPool;
+    svl::SharedStringPool maStrPool;
     NumArrayStoreType maNumArrays;
     StrArrayStoreType maStrArrays;
 };
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 3e7239e..eb61b90 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -65,7 +65,7 @@
 #include <svx/svdocirc.hxx>
 #include <svx/svdopath.hxx>
 #include "svl/srchitem.hxx"
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 
 #include <sfx2/docfile.hxx>
 
@@ -502,7 +502,7 @@ void Test::testCellStringPool()
     CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", nId1 == nId2);
 
     // Check the string counts after purging. Purging shouldn't remove any strings in this case.
-    svl::StringPool& rPool = m_pDoc->GetCellStringPool();
+    svl::SharedStringPool& rPool = m_pDoc->GetCellStringPool();
     rPool.purge();
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 6c964ca..c651cca 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -57,7 +57,7 @@
 #include <svl/zforlist.hxx>
 #include <svl/zformat.hxx>
 #include <svl/broadcast.hxx>
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 #include "editeng/editstat.hxx"
 
 #include <cstdio>
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index ea00606..0fb6755 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -35,7 +35,7 @@
 #include <vcl/virdev.hxx>
 #include <comphelper/processfactory.hxx>
 #include <svl/PasswordHelper.hxx>
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 #include <tools/tenccvt.hxx>
 #include <tools/urlobj.hxx>
 #include <rtl/crc.h>
@@ -119,7 +119,7 @@ private:
 // STATIC DATA -----------------------------------------------------------
 
 ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
-        mpCellStringPool(new svl::StringPool(ScGlobal::pCharClass)),
+        mpCellStringPool(new svl::SharedStringPool(ScGlobal::pCharClass)),
         mpUndoManager( NULL ),
         pEditEngine( NULL ),
         pNoteEngine( NULL ),
@@ -600,12 +600,12 @@ ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
     return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row());
 }
 
-svl::StringPool& ScDocument::GetCellStringPool()
+svl::SharedStringPool& ScDocument::GetCellStringPool()
 {
     return *mpCellStringPool;
 }
 
-const svl::StringPool& ScDocument::GetCellStringPool() const
+const svl::SharedStringPool& ScDocument::GetCellStringPool() const
 {
     return *mpCellStringPool;
 }
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index 4c9157d..4822557 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -17,7 +17,7 @@
 #include "mtvelements.hxx"
 #include "tokenarray.hxx"
 
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 
 struct ScDocumentImportImpl
 {
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 7026a46..6bf0093 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -60,7 +60,7 @@
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 
 #include <stdlib.h>
 #include <string.h>
diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk
index eddabf0..dc2bf41 100644
--- a/svl/Library_svl.mk
+++ b/svl/Library_svl.mk
@@ -110,7 +110,7 @@ $(eval $(call gb_Library_add_exception_objects,svl,\
     svl/source/misc/lockfilecommon \
     svl/source/misc/ownlist \
     svl/source/misc/sharecontrolfile \
-    svl/source/misc/stringpool \
+    svl/source/misc/sharedstringpool \
     svl/source/misc/strmadpt \
     svl/source/misc/urihelper \
     svl/source/notify/brdcst \
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index a34bb47..fe987ec 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -33,7 +33,7 @@
 
 #include "svl/zforlist.hxx"
 #include "svl/zformat.hxx"
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 #include "unotools/syslocale.hxx"
 
 #include <boost/scoped_ptr.hpp>
@@ -299,7 +299,7 @@ void Test::testNumberFormat()
 void Test::testStringPool()
 {
     SvtSysLocale aSysLocale;
-    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+    svl::SharedStringPool aPool(aSysLocale.GetCharClassPtr());
 
     const rtl_uString* p1 = aPool.intern("Andy");
     const rtl_uString* p2 = aPool.intern("Andy");
@@ -342,7 +342,7 @@ void Test::testStringPool()
 void Test::testStringPoolPurge()
 {
     SvtSysLocale aSysLocale;
-    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+    svl::SharedStringPool aPool(aSysLocale.GetCharClassPtr());
     aPool.intern("Andy");
     aPool.intern("andy");
     aPool.intern("ANDY");
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/sharedstringpool.cxx
similarity index 83%
rename from svl/source/misc/stringpool.cxx
rename to svl/source/misc/sharedstringpool.cxx
index 7ebc207..805a6fc 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/sharedstringpool.cxx
@@ -7,15 +7,15 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#include "svl/stringpool.hxx"
+#include "svl/sharedstringpool.hxx"
 #include "unotools/charclass.hxx"
 
 namespace svl {
 
-StringPool::StringPool() : mpCharClass(NULL) {}
-StringPool::StringPool( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
+SharedStringPool::SharedStringPool() : mpCharClass(NULL) {}
+SharedStringPool::SharedStringPool( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
 
-rtl_uString* StringPool::intern( const OUString& rStr )
+rtl_uString* SharedStringPool::intern( const OUString& rStr )
 {
     InsertResultType aRes = findOrInsert(maStrPool, rStr);
     if (aRes.first == maStrPool.end())
@@ -45,13 +45,13 @@ rtl_uString* StringPool::intern( const OUString& rStr )
     return pOrig;
 }
 
-sal_uIntPtr StringPool::getIdentifier( const OUString& rStr ) const
+sal_uIntPtr SharedStringPool::getIdentifier( const OUString& rStr ) const
 {
     StrHashType::const_iterator it = maStrPool.find(rStr);
     return (it == maStrPool.end()) ? 0 : reinterpret_cast<sal_uIntPtr>(it->pData);
 }
 
-sal_uIntPtr StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+sal_uIntPtr SharedStringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
     StrHashType::const_iterator itOrig = maStrPool.find(rStr);
     if (itOrig == maStrPool.end())
@@ -76,7 +76,7 @@ inline sal_Int32 getRefCount( const rtl_uString* p )
 
 }
 
-void StringPool::purge()
+void SharedStringPool::purge()
 {
     StrHashType aNewStrPool;
     StrHashType::iterator it = maStrPool.begin(), itEnd = maStrPool.end();
@@ -111,17 +111,17 @@ void StringPool::purge()
     maStrPoolUpper.swap(aNewStrPool);
 }
 
-size_t StringPool::getCount() const
+size_t SharedStringPool::getCount() const
 {
     return maStrPool.size();
 }
 
-size_t StringPool::getCountIgnoreCase() const
+size_t SharedStringPool::getCountIgnoreCase() const
 {
     return maStrPoolUpper.size();
 }
 
-StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
+SharedStringPool::InsertResultType SharedStringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
 {
     StrHashType::iterator it = rPool.find(rStr);
     bool bInserted = false;
commit 200b4539677b51cb7161a5dd4697778dbfc693e3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 4 15:21:36 2013 -0400

    Some attempt to store string ID's into query items.
    
    Change-Id: I8db7cd327728be0974405eabb0fd58156ba231d6

diff --git a/sc/inc/queryentry.hxx b/sc/inc/queryentry.hxx
index a3baea6..636372e 100644
--- a/sc/inc/queryentry.hxx
+++ b/sc/inc/queryentry.hxx
@@ -42,8 +42,9 @@ struct SC_DLLPUBLIC ScQueryEntry
         QueryType     meType;
         double        mfVal;
         OUString maString;
+        sal_uIntPtr mnStrId;
 
-        Item() : meType(ByValue), mfVal(0.0) {}
+        Item() : meType(ByValue), mfVal(0.0), mnStrId(0) {}
 
         bool operator== (const Item& r) const;
     };
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index fd2600e..7026a46 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -60,6 +60,7 @@
 
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
+#include "svl/stringpool.hxx"
 
 #include <stdlib.h>
 #include <string.h>
@@ -6448,6 +6449,43 @@ void ScInterpreter::ScHLookup()
     CalculateLookup(true);
 }
 
+namespace {
+
+#if 1
+bool isFilterByEqualString( const ScQueryParam& )
+{
+    return false;
+}
+#else
+bool isFilterByEqualString( const ScQueryParam& rParam )
+{
+    if (rParam.bRegExp)
+        // filter by regular expression.
+        return false;
+
+    if (!rParam.GetEntryCount())
+        // No entries.
+        return false;
+
+    const ScQueryEntry& rEntry = rParam.GetEntry(0);
+    if (rEntry.eOp != SC_EQUAL)
+        return false;
+
+    const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+    if (rItems.size() != 1)
+        // Multi-item query is not supported.
+        return false;
+
+    if (rItems[0].meType != ScQueryEntry::ByString)
+        // Not by string equality.
+        return false;
+
+    return true;
+}
+#endif
+
+}
+
 void ScInterpreter::CalculateLookup(bool bHLookup)
 {
     sal_uInt8 nParamCount = GetByte();
@@ -6684,9 +6722,18 @@ void ScInterpreter::CalculateLookup(bool bHLookup)
         }
         else
         {
-            ScAddress aResultPos( nCol1, nRow1, nTab1);
-            bFound = LookupQueryWithCache( aResultPos, aParam);
-            nRow = aResultPos.Row();
+            if (isFilterByEqualString(aParam))
+            {
+                nRow = nRow1;
+                bFound = true;
+            }
+            else
+            {
+                ScAddress aResultPos( nCol1, nRow1, nTab1);
+                bFound = LookupQueryWithCache( aResultPos, aParam);
+                nRow = aResultPos.Row();
+            }
+
             nCol = nSpIndex;
         }
 
@@ -6716,6 +6763,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
             const OUString& sStr = GetString();
             rItem.meType = ScQueryEntry::ByString;
             rItem.maString = sStr;
+            rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
         }
         break;
         case svDoubleRef :
@@ -6740,6 +6788,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
                 GetCellString(aStr, aCell);
                 rItem.meType = ScQueryEntry::ByString;
                 rItem.maString = aStr;
+                rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
             }
         }
         break;
@@ -6748,6 +6797,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
             OUString aStr;
             const ScMatValType nType = GetDoubleOrStringFromMatrix(rItem.mfVal, aStr);
             rItem.maString = aStr;
+            rItem.mnStrId = pDok->GetCellStringPool().getIdentifierIgnoreCase(rItem.maString);
             rItem.meType = ScMatrix::IsNonValueType(nType) ?
                 ScQueryEntry::ByString : ScQueryEntry::ByValue;
         }
diff --git a/sc/source/core/tool/queryentry.cxx b/sc/source/core/tool/queryentry.cxx
index 1ac1a89..e061d0f 100644
--- a/sc/source/core/tool/queryentry.cxx
+++ b/sc/source/core/tool/queryentry.cxx
@@ -32,7 +32,7 @@
 
 bool ScQueryEntry::Item::operator== (const Item& r) const
 {
-    return meType == r.meType && mfVal == r.mfVal && maString.equals(r.maString);
+    return meType == r.meType && mfVal == r.mfVal && maString.equals(r.maString) && mnStrId == r.mnStrId;
 }
 
 ScQueryEntry::ScQueryEntry() :
commit f54cdb59217cb84033235e18a208c6e27d7fca57
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Oct 4 13:18:12 2013 -0400

    ScInterpreter::GetString() now returns a ref to OUString.
    
    Making adjustments in some call sites.
    
    Change-Id: I85aca2eeb2aece46be52d90a611a64d85792a05f

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index c21e113..fd2600e 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -591,7 +591,7 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
                 break;
                 case svString:
                 {
-                    const String& rStr = GetString();
+                    const OUString& rStr = GetString();
                     if ( nGlobalError )
                     {
                         pResMat->PutDouble( CreateDoubleError( nGlobalError),
@@ -3150,7 +3150,7 @@ void ScInterpreter::ScTrim()
 
 void ScInterpreter::ScUpper()
 {
-    String aString = ScGlobal::pCharClass->uppercase(GetString());
+    OUString aString = ScGlobal::pCharClass->uppercase(GetString());
     PushString(aString);
 }
 
@@ -3182,15 +3182,15 @@ void ScInterpreter::ScPropper()
 
 void ScInterpreter::ScLower()
 {
-    String aString = ScGlobal::pCharClass->lowercase(GetString());
+    OUString aString = ScGlobal::pCharClass->lowercase(GetString());
     PushString(aString);
 }
 
 
 void ScInterpreter::ScLen()
 {
-    String aStr( GetString() );
-    PushDouble( aStr.Len() );
+    const OUString& aStr = GetString();
+    PushDouble( aStr.getLength() );
 }
 
 
@@ -3456,7 +3456,7 @@ void ScInterpreter::ScClean()
 void ScInterpreter::ScCode()
 {
 //2do: make it full range unicode?
-    const String& rStr = GetString();
+    String aStr = GetString();
     //"classic" ByteString conversion flags
     const sal_uInt32 convertFlags =
         RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE |
@@ -3465,7 +3465,7 @@ void ScInterpreter::ScCode()
         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
         RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE;
-    PushInt( (sal_uChar) OUStringToOString(OUString(rStr.GetChar(0)), osl_getThreadTextEncoding(), convertFlags).toChar() );
+    PushInt( (sal_uChar) OUStringToOString(OUString(aStr.GetChar(0)), osl_getThreadTextEncoding(), convertFlags).toChar() );
 }
 
 
@@ -6713,7 +6713,7 @@ bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
         break;
         case svString:
         {
-            const String& sStr = GetString();
+            const OUString& sStr = GetString();
             rItem.meType = ScQueryEntry::ByString;
             rItem.maString = sStr;
         }
@@ -8262,11 +8262,11 @@ void ScInterpreter::ScMid()
     {
         double fAnz    = ::rtl::math::approxFloor(GetDouble());
         double fAnfang = ::rtl::math::approxFloor(GetDouble());
-        const String& rStr = GetString();
+        String aStr = GetString();
         if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
             PushIllegalArgument();
         else
-            PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
+            PushString(aStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
     }
 }
 
@@ -8275,7 +8275,7 @@ void ScInterpreter::ScText()
 {
     if ( MustHaveParamCount( GetByte(), 2 ) )
     {
-        OUString sFormatString = GetString();
+        const OUString& sFormatString = GetString();
         OUString aStr;
         bool bString = false;
         double fVal = 0.0;
@@ -8432,7 +8432,7 @@ void ScInterpreter::ScConcat()
     String aRes;
     while( nParamCount-- > 0)
     {
-        const String& rStr = GetString();
+        const OUString& rStr = GetString();
         aRes.Insert( rStr, 0 );
     }
     PushString( aRes );
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index 4eb4075..6f08958 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -162,7 +162,7 @@ void ScInterpreter::ScGetHour()
 
 void ScInterpreter::ScGetDateValue()
 {
-    String aInputString = GetString();
+    const OUString& aInputString = GetString();
     sal_uInt32 nFIndex = 0;                 // damit default Land/Spr.
     double fVal;
     if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
@@ -388,7 +388,7 @@ void ScInterpreter::ScGetDateDif()
 {
     if ( MustHaveParamCount( GetByte(), 3 ) )
     {
-        OUString aInterval = GetString();
+        const OUString& aInterval = GetString();
         double nDate2    = GetDouble();
         double nDate1    = GetDouble();
 
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index ec37683..fedda31 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -2726,7 +2726,7 @@ void ScInterpreter::ScExternal()
                     break;
 
                 case SC_ADDINARG_STRING:
-                    aParam <<= OUString( GetString() );
+                    aParam <<= GetString();
                     break;
 
                 case SC_ADDINARG_INTEGER_ARRAY:
@@ -2806,7 +2806,7 @@ void ScInterpreter::ScExternal()
                         case svString:
                         case svSingleRef:
                             {
-                                OUString aString = OUString( GetString() );
+                                const OUString& aString = GetString();
                                 uno::Sequence<OUString> aInner( &aString, 1 );
                                 uno::Sequence< uno::Sequence<OUString> > aOuter( &aInner, 1 );
                                 aParam <<= aOuter;
@@ -2841,7 +2841,7 @@ void ScInterpreter::ScExternal()
                                 if ( nStackType == svDouble )
                                     aElem <<= (double) GetDouble();
                                 else if ( nStackType == svString )
-                                    aElem <<= OUString( GetString() );
+                                    aElem <<= GetString();
                                 else
                                 {
                                     ScAddress aAdr;
@@ -2891,7 +2891,7 @@ void ScInterpreter::ScExternal()
                             aParam <<= (double) GetDouble();
                             break;
                         case svString:
-                            aParam <<= OUString( GetString() );
+                            aParam <<= GetString();
                             break;
                         case svSingleRef:
                             {
commit 8d7973f8f14e07ddbe77e3633a5de641fa38e379
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 15:53:18 2013 -0400

    Reduce the amount of indentation by early exit.
    
    Change-Id: Ibcf64f57d84dd90a41421522c8082319f1d5796a

diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index f1988d6..1935c3b 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -688,7 +688,7 @@ bool CalculateTest( bool _bTemplin
                    ,const SCSIZE nC1, const SCSIZE nC2,const SCSIZE nR1,const SCSIZE nR2
                    ,const ScMatrixRef& pMat1,const ScMatrixRef& pMat2
                    ,double& fT,double& fF);
-void CalculateLookup(bool HLookup);
+void CalculateLookup(bool bHLookup);
 bool FillEntry(ScQueryEntry& rEntry);
 void CalculateAddSub(bool _bSub);
 void CalculateTrendGrowth(bool _bGrowth);
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 7025b00..c21e113 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -6447,249 +6447,256 @@ void ScInterpreter::ScHLookup()
 {
     CalculateLookup(true);
 }
-void ScInterpreter::CalculateLookup(bool HLookup)
+
+void ScInterpreter::CalculateLookup(bool bHLookup)
 {
     sal_uInt8 nParamCount = GetByte();
-    if ( MustHaveParamCount( nParamCount, 3, 4 ) )
+    if (!MustHaveParamCount(nParamCount, 3, 4))
+        return;
+
+    // Optional 4th argument to declare whether or not the range is sorted.
+    bool bSorted = true;
+    if (nParamCount == 4)
+        bSorted = GetBool();
+
+    // Index of column to search.
+    double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
+
+    ScMatrixRef pMat = NULL;
+    SCSIZE nC = 0, nR = 0;
+    SCCOL nCol1 = 0;
+    SCROW nRow1 = 0;
+    SCTAB nTab1 = 0;
+    SCCOL nCol2 = 0;
+    SCROW nRow2 = 0;
+    SCTAB nTab2;
+    StackVar eType = GetStackType();
+    if (eType == svDoubleRef)
     {
-        bool bSorted;
-        if (nParamCount == 4)
-            bSorted = GetBool();
-        else
-            bSorted = true;
-        double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
-        ScMatrixRef pMat = NULL;
-        SCSIZE nC = 0, nR = 0;
-        SCCOL nCol1 = 0;
-        SCROW nRow1 = 0;
-        SCTAB nTab1 = 0;
-        SCCOL nCol2 = 0;
-        SCROW nRow2 = 0;
-        SCTAB nTab2;
-        StackVar eType = GetStackType();
-        if (eType == svDoubleRef)
-        {
-            PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
-            if (nTab1 != nTab2)
-            {
-                PushIllegalParameter();
-                return;
-            }
-        }
-        else if (eType == svSingleRef)
+        PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+        if (nTab1 != nTab2)
         {
-            PopSingleRef(nCol1, nRow1, nTab1);
-            nCol2 = nCol1;
-            nRow2 = nRow1;
+            PushIllegalParameter();
+            return;
         }
-        else if (eType == svMatrix || eType == svExternalDoubleRef || eType == svExternalSingleRef)
-        {
-            pMat = GetMatrix();
+    }
+    else if (eType == svSingleRef)
+    {
+        PopSingleRef(nCol1, nRow1, nTab1);
+        nCol2 = nCol1;
+        nRow2 = nRow1;
+    }
+    else if (eType == svMatrix || eType == svExternalDoubleRef || eType == svExternalSingleRef)
+    {
+        pMat = GetMatrix();
 
-            if (pMat)
-                pMat->GetDimensions(nC, nR);
-            else
-            {
-                PushIllegalParameter();
-                return;
-            }
-        }
+        if (pMat)
+            pMat->GetDimensions(nC, nR);
         else
         {
             PushIllegalParameter();
             return;
         }
-        if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
-        {
-            PushIllegalArgument();
-            return;
-        }
-        SCROW nZIndex = static_cast<SCROW>(fIndex);
-        SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
+    }
+    else
+    {
+        PushIllegalParameter();
+        return;
+    }
 
-        if (!pMat)
-        {
-            nZIndex += nRow1;                       // Wertzeile
-            nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
-        }
+    if ( fIndex < 0.0 || (bHLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
+    {
+        PushIllegalArgument();
+        return;
+    }
 
-        if (nGlobalError == 0)
-        {
-            ScQueryParam rParam;
-            rParam.nCol1       = nCol1;
-            rParam.nRow1       = nRow1;
-            if ( HLookup )
-            {
-                rParam.nCol2       = nCol2;
-                rParam.nRow2       = nRow1;     // nur in der ersten Zeile suchen
-                rParam.bByRow      = false;
-            } // if ( HLookup )
-            else
-            {
-                rParam.nCol2       = nCol1;     // nur in der ersten Spalte suchen
-                rParam.nRow2       = nRow2;
-                rParam.nTab        = nTab1;
-            }
+    SCROW nZIndex = static_cast<SCROW>(fIndex);
+    SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
 
-            ScQueryEntry& rEntry = rParam.GetEntry(0);
-            rEntry.bDoQuery = true;
-            if ( bSorted )
-                rEntry.eOp = SC_LESS_EQUAL;
-            if ( !FillEntry(rEntry) )
-                return;
+    if (!pMat)
+    {
+        nZIndex += nRow1;                       // Wertzeile
+        nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
+    }
 
-            ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
-            if (rItem.meType == ScQueryEntry::ByString)
-                rParam.bRegExp = MayBeRegExp(rItem.maString, pDok);
-            if (pMat)
+    if (nGlobalError)
+    {
+        PushIllegalParameter();
+        return;
+    }
+
+    ScQueryParam aParam;
+    aParam.nCol1 = nCol1;
+    aParam.nRow1 = nRow1;
+    if ( bHLookup )
+    {
+        aParam.nCol2 = nCol2;
+        aParam.nRow2 = nRow1;     // nur in der ersten Zeile suchen
+        aParam.bByRow = false;
+    }
+    else
+    {
+        aParam.nCol2 = nCol1;     // nur in der ersten Spalte suchen
+        aParam.nRow2 = nRow2;
+        aParam.nTab  = nTab1;
+    }
+
+    ScQueryEntry& rEntry = aParam.GetEntry(0);
+    rEntry.bDoQuery = true;
+    if ( bSorted )
+        rEntry.eOp = SC_LESS_EQUAL;
+    if ( !FillEntry(rEntry) )
+        return;
+
+    ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+    if (rItem.meType == ScQueryEntry::ByString)
+        aParam.bRegExp = MayBeRegExp(rItem.maString, pDok);
+    if (pMat)
+    {
+        SCSIZE nMatCount = bHLookup ? nC : nR;
+        SCSIZE nDelta = SCSIZE_MAX;
+        if (rItem.meType == ScQueryEntry::ByString)
+        {
+//!!!!!!!
+//! TODO: enable regex on matrix strings
+//!!!!!!!
+            const OUString& rParamStr = rItem.maString;
+            if ( bSorted )
             {
-                SCSIZE nMatCount = HLookup ? nC : nR;
-                SCSIZE nDelta = SCSIZE_MAX;
-                if (rItem.meType == ScQueryEntry::ByString)
+                static CollatorWrapper* pCollator = ScGlobal::GetCollator();
+                for (SCSIZE i = 0; i < nMatCount; i++)
                 {
-        //!!!!!!!
-        //! TODO: enable regex on matrix strings
-        //!!!!!!!
-                    const OUString& rParamStr = rItem.maString;
-                    if ( bSorted )
+                    if (bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
                     {
-                        static CollatorWrapper* pCollator = ScGlobal::GetCollator();
-                        for (SCSIZE i = 0; i < nMatCount; i++)
-                        {
-                            if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
-                            {
-                                sal_Int32 nRes =
-                                    pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), rParamStr);
-                                if (nRes <= 0)
-                                    nDelta = i;
-                                else if (i>0)   // #i2168# ignore first mismatch
-                                    i = nMatCount+1;
-                            }
-                            else
-                                nDelta = i;
-                        }
+                        sal_Int32 nRes =
+                            pCollator->compareString( bHLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), rParamStr);
+                        if (nRes <= 0)
+                            nDelta = i;
+                        else if (i>0)   // #i2168# ignore first mismatch
+                            i = nMatCount+1;
                     }
                     else
+                        nDelta = i;
+                }
+            }
+            else
+            {
+                if (bHLookup)
+                {
+                    for (SCSIZE i = 0; i < nMatCount; i++)
                     {
-                        if (HLookup)
+                        if (pMat->IsString(i, 0))
                         {
-                            for (SCSIZE i = 0; i < nMatCount; i++)
+                            if ( ScGlobal::GetpTransliteration()->isEqual(
+                                pMat->GetString(i,0), rParamStr))
                             {
-                                if (pMat->IsString(i, 0))
-                                {
-                                    if ( ScGlobal::GetpTransliteration()->isEqual(
-                                        pMat->GetString(i,0), rParamStr))
-                                    {
-                                        nDelta = i;
-                                        i = nMatCount + 1;
-                                    }
-                                }
+                                nDelta = i;
+                                i = nMatCount + 1;
                             }
                         }
-                        else
-                        {
-                            nDelta = pMat->MatchStringInColumns(rParamStr, 0, 0);
-                        }
                     }
                 }
                 else
                 {
-                    if ( bSorted )
-                    {
-                        // #i2168# ignore strings
-                        for (SCSIZE i = 0; i < nMatCount; i++)
-                        {
-                            if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
-                            {
-                                if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rItem.mfVal)
-                                    nDelta = i;
-                                else
-                                    i = nMatCount+1;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        if (HLookup)
-                        {
-                            for (SCSIZE i = 0; i < nMatCount; i++)
-                            {
-                                if (! pMat->IsString(i, 0) )
-                                {
-                                    if ( pMat->GetDouble(i,0) == rItem.mfVal)
-                                    {
-                                        nDelta = i;
-                                        i = nMatCount + 1;
-                                    }
-                                }
-                            }
-                        }
-                        else
-                        {
-                            nDelta = pMat->MatchDoubleInColumns(rItem.mfVal, 0, 0);
-                        }
-                    }
+                    nDelta = pMat->MatchStringInColumns(rParamStr, 0, 0);
                 }
-                if ( nDelta != SCSIZE_MAX )
+            }
+        }
+        else
+        {
+            if ( bSorted )
+            {
+                // #i2168# ignore strings
+                for (SCSIZE i = 0; i < nMatCount; i++)
                 {
-                    SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
-                    SCSIZE nY = nDelta;
-                    if ( HLookup )
+                    if (!(bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
                     {
-                        nX = nDelta;
-                        nY = static_cast<SCSIZE>(nZIndex);
+                        if ((bHLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rItem.mfVal)
+                            nDelta = i;
+                        else
+                            i = nMatCount+1;
                     }
-                    if ( pMat->IsString( nX, nY) )
-                        PushString(pMat->GetString( nX,nY));
-                    else
-                        PushDouble(pMat->GetDouble( nX,nY));
                 }
-                else
-                    PushNA();
             }
             else
             {
-                rEntry.nField = nCol1;
-                bool bFound = false;
-                SCCOL nCol = 0;
-                SCROW nRow = 0;
-                if ( bSorted )
-                    rEntry.eOp = SC_LESS_EQUAL;
-                if ( HLookup )
+                if (bHLookup)
                 {
-                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
-                    // advance Entry.nField in Iterator upon switching columns
-                    aCellIter.SetAdvanceQueryParamEntryField( true );
-                    if ( bSorted )
-                    {
-                        SCROW nRow1_temp;
-                        bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
-                    }
-                    else if ( aCellIter.GetFirst() )
+                    for (SCSIZE i = 0; i < nMatCount; i++)
                     {
-                        bFound = true;
-                        nCol = aCellIter.GetCol();
+                        if (! pMat->IsString(i, 0) )
+                        {
+                            if ( pMat->GetDouble(i,0) == rItem.mfVal)
+                            {
+                                nDelta = i;
+                                i = nMatCount + 1;
+                            }
+                        }
                     }
-                    nRow = nZIndex;
-                } // if ( HLookup )
-                else
-                {
-                    ScAddress aResultPos( nCol1, nRow1, nTab1);
-                    bFound = LookupQueryWithCache( aResultPos, rParam);
-                    nRow = aResultPos.Row();
-                    nCol = nSpIndex;
                 }
-                if ( bFound )
+                else
                 {
-                    ScAddress aAdr( nCol, nRow, nTab1 );
-                    PushCellResultToken( true, aAdr, NULL, NULL);
+                    nDelta = pMat->MatchDoubleInColumns(rItem.mfVal, 0, 0);
                 }
-                else
-                    PushNA();
             }
         }
+        if ( nDelta != SCSIZE_MAX )
+        {
+            SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
+            SCSIZE nY = nDelta;
+            if ( bHLookup )
+            {
+                nX = nDelta;
+                nY = static_cast<SCSIZE>(nZIndex);
+            }
+            if ( pMat->IsString( nX, nY) )
+                PushString(pMat->GetString( nX,nY));
+            else
+                PushDouble(pMat->GetDouble( nX,nY));
+        }
         else
-            PushIllegalParameter();
+            PushNA();
+    }
+    else
+    {
+        rEntry.nField = nCol1;
+        bool bFound = false;
+        SCCOL nCol = 0;
+        SCROW nRow = 0;
+        if ( bSorted )
+            rEntry.eOp = SC_LESS_EQUAL;
+        if ( bHLookup )
+        {
+            ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
+            // advance Entry.nField in Iterator upon switching columns
+            aCellIter.SetAdvanceQueryParamEntryField( true );
+            if ( bSorted )
+            {
+                SCROW nRow1_temp;
+                bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
+            }
+            else if ( aCellIter.GetFirst() )
+            {
+                bFound = true;
+                nCol = aCellIter.GetCol();
+            }
+            nRow = nZIndex;
+        }
+        else
+        {
+            ScAddress aResultPos( nCol1, nRow1, nTab1);
+            bFound = LookupQueryWithCache( aResultPos, aParam);
+            nRow = aResultPos.Row();
+            nCol = nSpIndex;
+        }
+
+        if ( bFound )
+        {
+            ScAddress aAdr( nCol, nRow, nTab1 );
+            PushCellResultToken( true, aAdr, NULL, NULL);
+        }
+        else
+            PushNA();
     }
 }
 
commit 3f6f7566dd92be7b27cee99d3291fdb4fc5f5a38
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 14:58:06 2013 -0400

    Test comparison between simple and rich-text string values.
    
    Change-Id: Icdb9a81b1be80b058b71c23b3fcb58a5e8970e21

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index ba9a78e..3e7239e 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -57,6 +57,8 @@
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <editeng/boxitem.hxx>
 #include <editeng/brushitem.hxx>
+#include "editeng/wghtitem.hxx"
+#include "editeng/postitem.hxx"
 
 #include <svx/svdograf.hxx>
 #include <svx/svdpage.hxx>
@@ -535,6 +537,56 @@ void Test::testCellStringPool()
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
 
+    // Now, compare string and edit text cells.
+    m_pDoc->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
+    ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
+    rEE.SetText("Andy and Bruce");
+
+    ESelection aSel;
+    aSel.nStartPara = aSel.nEndPara = 0;
+
+    {
+        // Set 'Andy' bold.
+        SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+        aSel.nStartPos = 0;
+        aSel.nEndPos = 4;
+        SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+        aItemSet.Put(aWeight);
+        rEE.QuickSetAttribs(aItemSet, aSel);
+    }
+
+    {
+        // Set 'Bruce' italic.
+        SfxItemSet aItemSet = rEE.GetEmptyItemSet();
+        SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
+        aItemSet.Put(aItalic);
+        aSel.nStartPos = 9;
+        aSel.nEndPos = 14;
+        rEE.QuickSetAttribs(aItemSet, aSel);
+    }
+
+    m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject()); // B1
+
+    // These two should be equal.
+    nId1 = m_pDoc->GetCellStringID(ScAddress(0,0,0));
+    nId2 = m_pDoc->GetCellStringID(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
+    rEE.SetText("ANDY and BRUCE");
+    m_pDoc->SetEditText(ScAddress(2,0,0), rEE.CreateTextObject()); // C1
+    nId2 = m_pDoc->GetCellStringID(ScAddress(2,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", nId1 != nId2);
+
+    // But they should be considered equal when cases are ignored.
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,0,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(2,0,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
     m_pDoc->DeleteTab(0);
 }
 
commit 875f47cb5a20e2ce6ed54d88fd5bbf1d6128a47d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 14:24:28 2013 -0400

    Add methods to turn cell strings into numeric IDs for comparison.
    
    Both in case sensitive and case insensitive comparisons.
    
    Change-Id: I356a655273f0f37157810c86e1cf3f87ea2afa09

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6d09ad1..2f4d697 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -280,6 +280,9 @@ public:
     ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell );
     bool SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell );
 
+    sal_uIntPtr GetCellStringID( SCROW nRow ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( SCROW nRow ) const;
+
     void SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast = true );
     void SetRawString( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast = true );
     void SetValue( SCROW nRow, double fVal );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 6828d4d..2ef6073 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -436,7 +436,6 @@ public:
     sal_uLong           GetCodeCount() const;       // RPN-Code in formulas
     DECL_LINK( GetUserDefinedColor, sal_uInt16 * );
                                                                 // number formatter
-
 public:
     SC_DLLPUBLIC                ScDocument( ScDocumentMode eMode = SCDOCMODE_DOCUMENT,
                                 SfxObjectShell* pDocShell = NULL );
@@ -860,6 +859,11 @@ public:
      */
     double* GetValueCell( const ScAddress& rPos );
 
+    svl::StringPool& GetCellStringPool();
+    const svl::StringPool& GetCellStringPool() const;
+    sal_uIntPtr GetCellStringID( const ScAddress& rPos ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( const ScAddress& rPos ) const;
+
     SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString );
     SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString );
     sal_uInt16 GetStringForFormula( const ScAddress& rPos, OUString& rString );
@@ -2066,8 +2070,6 @@ private: // CLOOK-Impl-methods
 
     ScRefCellValue GetRefCellValue( const ScAddress& rPos );
 
-    svl::StringPool& GetCellStringPool();
-
     std::map< SCTAB, ScSortParam > mSheetSortParams;
 
 };
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 7ae03f2..7d5fa1e 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -343,6 +343,9 @@ public:
     ScFormulaCell* SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
     bool SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
 
+    sal_uIntPtr GetCellStringID( SCCOL nCol, SCROW nRow ) const;
+    sal_uIntPtr GetCellStringIDIgnoreCase( SCCOL nCol, SCROW nRow ) const;
+
     void        SetValue( SCCOL nCol, SCROW nRow, const double& rVal );
     void        SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError);
 
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 8d2266e..ba9a78e 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -63,6 +63,7 @@
 #include <svx/svdocirc.hxx>
 #include <svx/svdopath.hxx>
 #include "svl/srchitem.hxx"
+#include "svl/stringpool.hxx"
 
 #include <sfx2/docfile.hxx>
 
@@ -458,6 +459,85 @@ void Test::testCollator()
     CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes != 0);
 }
 
+void Test::testCellStringPool()
+{
+    m_pDoc->InsertTab(0, "foo");
+
+    // Strings that are identical.
+    m_pDoc->SetString(ScAddress(0,0,0), "Andy");  // A1
+    m_pDoc->SetString(ScAddress(0,1,0), "Andy");  // A2
+    m_pDoc->SetString(ScAddress(0,2,0), "Bruce"); // A3
+    m_pDoc->SetString(ScAddress(0,3,0), "andy");  // A4
+    m_pDoc->SetString(ScAddress(0,4,0), "BRUCE"); // A5
+
+    sal_uIntPtr nId1 = m_pDoc->GetCellStringID(ScAddress(0,0,0));
+    sal_uIntPtr nId2 = m_pDoc->GetCellStringID(ScAddress(0,1,0));
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId1);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", nId2);
+    CPPUNIT_ASSERT_EQUAL(nId1, nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,2,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,3,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    // A3 and A5 should differ but should be equal case-insensitively.
+    nId1 = m_pDoc->GetCellStringID(ScAddress(0,2,0));
+    nId2 = m_pDoc->GetCellStringID(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must differ", nId1 != nId2);
+
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,2,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,4,0));
+    CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", nId1 == nId2);
+
+    // A2 and A4 should be equal when ignoring cases.
+    nId1 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,1,0));
+    nId2 = m_pDoc->GetCellStringIDIgnoreCase(ScAddress(0,3,0));
+    CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", nId1 == nId2);
+
+    // Check the string counts after purging. Purging shouldn't remove any strings in this case.
+    svl::StringPool& rPool = m_pDoc->GetCellStringPool();
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A1 and purge again.
+    clearRange(m_pDoc, ScAddress(0,0,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A2 and purge again.
+    clearRange(m_pDoc, ScAddress(0,1,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A3 and purge again.
+    clearRange(m_pDoc, ScAddress(0,2,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
+
+    // Clear A4 and purge again.
+    clearRange(m_pDoc, ScAddress(0,3,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCountIgnoreCase());
+
+    // Clear A5 and the pool should be completely empty.
+    clearRange(m_pDoc, ScAddress(0,4,0));
+    rPool.purge();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testRangeList()
 {
     m_pDoc->InsertTab(0, "foo");
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index d01714e..d1ba668 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -80,6 +80,7 @@ public:
      */
     void testPerf();
     void testCollator();
+    void testCellStringPool();
     void testRangeList();
     void testInput();
 
@@ -284,6 +285,7 @@ public:
     CPPUNIT_TEST(testPerf);
 #endif
     CPPUNIT_TEST(testCollator);
+    CPPUNIT_TEST(testCellStringPool);
     CPPUNIT_TEST(testRangeList);
     CPPUNIT_TEST(testInput);
     CPPUNIT_TEST(testFormulaHashAndTag);
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index f5eccae..6c964ca 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1732,6 +1732,64 @@ bool ScColumn::SetGroupFormulaCell( SCROW nRow, ScFormulaCell* pCell )
     return true;
 }
 
+sal_uIntPtr ScColumn::GetCellStringID( SCROW nRow ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
+    switch (aPos.first->type)
+    {
+        case sc::element_type_string:
+        {
+            const OUString& rStr = sc::string_block::at(*aPos.first->data, aPos.second);
+            return pDocument->GetCellStringPool().getIdentifier(rStr);
+        }
+        break;
+        case sc::element_type_edittext:
+        {
+            std::vector<sal_uIntPtr> aIDs;
+            const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
+            pObj->GetStringIDs(pDocument->GetCellStringPool(), aIDs);
+            if (aIDs.size() != 1)
+                // We don't handle multiline content for now.
+                return 0;
+
+            return aIDs[0];
+        }
+        break;
+        default:
+            ;
+    }
+    return 0;
+}
+
+sal_uIntPtr ScColumn::GetCellStringIDIgnoreCase( SCROW nRow ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
+    switch (aPos.first->type)
+    {
+        case sc::element_type_string:
+        {
+            const OUString& rStr = sc::string_block::at(*aPos.first->data, aPos.second);
+            return pDocument->GetCellStringPool().getIdentifierIgnoreCase(rStr);
+        }
+        break;
+        case sc::element_type_edittext:
+        {
+            std::vector<sal_uIntPtr> aIDs;
+            const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
+            pObj->GetStringIDsIgnoreCase(pDocument->GetCellStringPool(), aIDs);
+            if (aIDs.size() != 1)
+                // We don't handle multiline content for now.
+                return 0;
+
+            return aIDs[0];
+        }
+        break;
+        default:
+            ;
+    }
+    return 0;
+}
+
 namespace {
 
 class FilterEntriesHandler
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 9f64090..ea00606 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -605,6 +605,11 @@ svl::StringPool& ScDocument::GetCellStringPool()
     return *mpCellStringPool;
 }
 
+const svl::StringPool& ScDocument::GetCellStringPool() const
+{
+    return *mpCellStringPool;
+}
+
 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
                                 bool bNotes ) const
 {
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index dc7db44..9b91290 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3221,6 +3221,22 @@ double* ScDocument::GetValueCell( const ScAddress& rPos )
     return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
 }
 
+sal_uIntPtr ScDocument::GetCellStringID( const ScAddress& rPos ) const
+{
+    if (!TableExists(rPos.Tab()))
+        return 0;
+
+    return maTabs[rPos.Tab()]->GetCellStringID(rPos.Col(), rPos.Row());
+}
+
+sal_uIntPtr ScDocument::GetCellStringIDIgnoreCase( const ScAddress& rPos ) const
+{
+    if (!TableExists(rPos.Tab()))
+        return 0;
+
+    return maTabs[rPos.Tab()]->GetCellStringIDIgnoreCase(rPos.Col(), rPos.Row());
+}
+
 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
 {
     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 24fc92b..9ec6977 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1505,6 +1505,22 @@ bool ScTable::SetGroupFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell
     return aCol[nCol].SetGroupFormulaCell(nRow, pCell);
 }
 
+sal_uIntPtr ScTable::GetCellStringID( SCCOL nCol, SCROW nRow ) const
+{
+    if (!ValidColRow(nCol, nRow))
+        return 0;
+
+    return aCol[nCol].GetCellStringID(nRow);
+}
+
+sal_uIntPtr ScTable::GetCellStringIDIgnoreCase( SCCOL nCol, SCROW nRow ) const
+{
+    if (!ValidColRow(nCol, nRow))
+        return 0;
+
+    return aCol[nCol].GetCellStringIDIgnoreCase(nRow);
+}
+
 void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
 {
     if (ValidColRow(nCol, nRow))
commit f6ec66727379fef56f0972e2a6181e39ab6d4ec1
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 12:16:22 2013 -0400

    Add methods to extract string IDs from edit text object.
    
    Note that a single edit text object may have multiple string ID's in case
    it consists of multiple paragraphs.
    
    Change-Id: Ie90541de38a639c30a010817dada389e9445d08c

diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index aaf5e5f..4e6af47 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -154,6 +154,16 @@ void ContentInfo::NormalizeString( svl::StringPool& rPool )
     aText = OUString(rPool.intern(aText));
 }
 
+sal_uIntPtr ContentInfo::GetStringID( const svl::StringPool& rPool ) const
+{
+    return rPool.getIdentifier(aText);
+}
+
+sal_uIntPtr ContentInfo::GetStringIDIgnoreCase( const svl::StringPool& rPool ) const
+{
+    return rPool.getIdentifierIgnoreCase(aText);
+}
+
 const WrongList* ContentInfo::GetWrongList() const
 {
     return mpWrongs.get();
@@ -327,6 +337,16 @@ void EditTextObject::NormalizeString( svl::StringPool& rPool )
     mpImpl->NormalizeString(rPool);
 }
 
+bool EditTextObject::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    return mpImpl->GetStringIDs(rPool, rIDs);
+}
+
+bool EditTextObject::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    return mpImpl->GetStringIDsIgnoreCase(rPool, rIDs);
+}
+
 const SfxItemPool* EditTextObject::GetPool() const
 {
     return mpImpl->GetPool();
@@ -623,6 +643,44 @@ void EditTextObjectImpl::NormalizeString( svl::StringPool& rPool )
     }
 }
 
+bool EditTextObjectImpl::GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    std::vector<sal_uIntPtr> aIDs;
+    aIDs.reserve(aContents.size());
+    ContentInfosType::const_iterator it = aContents.begin(), itEnd = aContents.end();
+    for (; it != itEnd; ++it)
+    {
+        const ContentInfo& rInfo = *it;
+        sal_uIntPtr nID = rInfo.GetStringID(rPool);
+        if (!nID)
+            return false;
+
+        aIDs.push_back(nID);
+    }
+
+    rIDs.swap(aIDs);
+    return true;
+}
+
+bool EditTextObjectImpl::GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const
+{
+    std::vector<sal_uIntPtr> aIDs;
+    aIDs.reserve(aContents.size());
+    ContentInfosType::const_iterator it = aContents.begin(), itEnd = aContents.end();
+    for (; it != itEnd; ++it)
+    {
+        const ContentInfo& rInfo = *it;
+        sal_uIntPtr nID = rInfo.GetStringIDIgnoreCase(rPool);
+        if (!nID)
+            return false;
+
+        aIDs.push_back(nID);
+    }
+
+    rIDs.swap(aIDs);
+    return true;
+}
+
 bool EditTextObjectImpl::IsVertical() const
 {
     return bVertical;
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index c331134..d2118d7 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -143,6 +143,8 @@ public:
                         ~ContentInfo();
 
     void NormalizeString( svl::StringPool& rPool );
+    sal_uIntPtr GetStringID( const svl::StringPool& rPool ) const;
+    sal_uIntPtr GetStringIDIgnoreCase( const svl::StringPool& rPool ) const;
 
     const XEditAttributesType& GetAttribs() const { return aAttribs; }
     XEditAttributesType& GetAttribs() { return aAttribs; }
@@ -207,6 +209,8 @@ public:
     void SetUserType( sal_uInt16 n );
 
     void NormalizeString( svl::StringPool& rPool );
+    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
 
     bool                    IsVertical() const;
     void                    SetVertical( bool b );
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index 36392e2..4751469 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -85,6 +85,9 @@ public:
      */
     void NormalizeString( svl::StringPool& rPool );
 
+    bool GetStringIDs( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+    bool GetStringIDsIgnoreCase( const svl::StringPool& rPool, std::vector<sal_uIntPtr>& rIDs ) const;
+
     const SfxItemPool* GetPool() const;
     sal_uInt16 GetUserType() const;    // For OutlinerMode, it can however not save in compatible format
     void SetUserType( sal_uInt16 n );
commit 4aa411674224edb5eedd8d6170e8b27c491df851
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 11:34:24 2013 -0400

    Let's just use sal_uIntPtr straight.
    
    So that the user of this class won't have to include the header just
    to get the string ID type.
    
    Change-Id: I0ccbc18fe02644f69701f57b0b1b9c30fd141d83

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index cac7637..fbcff1e 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -37,7 +37,6 @@ class SVL_DLLPUBLIC StringPool
     const CharClass* mpCharClass;
 
 public:
-    typedef sal_uIntPtr StrIdType;
 
     StringPool();
     StringPool( const CharClass* pCharClass );
@@ -61,7 +60,7 @@ public:
      *
      * @return unique ID of the string object.
      */
-    StrIdType getIdentifier( const OUString& rStr ) const;
+    sal_uIntPtr getIdentifier( const OUString& rStr ) const;
 
     /**
      * Get a unique ID of string object for case insensitive comparison. The
@@ -72,7 +71,7 @@ public:
      * @return unique ID of the string object usable for case insensitive
      *         comparison.
      */
-    StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
+    sal_uIntPtr getIdentifierIgnoreCase( const OUString& rStr ) const;
 
     /**
      * Go through all string objects in the pool, and clear those that are no
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 11a52e6..a34bb47 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -309,8 +309,8 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
 
     OUString aAndy("Andy");
-    svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
-    svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    sal_uIntPtr si1 = aPool.getIdentifier("Andy");
+    sal_uIntPtr si2 = aPool.getIdentifier(aAndy);
     CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si1);
     CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si2);
     CPPUNIT_ASSERT_EQUAL(si1, si2);
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 4760348..7ebc207 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -45,13 +45,13 @@ rtl_uString* StringPool::intern( const OUString& rStr )
     return pOrig;
 }
 
-StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
+sal_uIntPtr StringPool::getIdentifier( const OUString& rStr ) const
 {
     StrHashType::const_iterator it = maStrPool.find(rStr);
-    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<sal_uIntPtr>(it->pData);
 }
 
-StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+sal_uIntPtr StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
     StrHashType::const_iterator itOrig = maStrPool.find(rStr);
     if (itOrig == maStrPool.end())
@@ -64,7 +64,7 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
         return 0;
 
     const rtl_uString* pUpper = itUpper->second.pData;
-    return reinterpret_cast<StrIdType>(pUpper);
+    return reinterpret_cast<sal_uIntPtr>(pUpper);
 }
 
 namespace {
commit dc1314d96257845139015ee13edc04af470c18f6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Oct 3 10:55:48 2013 -0400

    Normalize all string objects that are cell contents before they get stored.
    
    Hopefully I've covered all entry points. There may be more lurking in some
    dark corneres...
    
    Change-Id: I62e655cc579aad08fa64b5d58e739c55425cd216

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 73d7c1c..6828d4d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -234,6 +234,7 @@ friend class ScDocRowHeightUpdater;
 friend class ScColumnTextWidthIterator;
 friend class ScFormulaCell;
 friend class ScTable;
+friend class ScColumn;
 friend struct ScRefCellValue;
 friend class ScDocumentImport;
 friend class sc::ColumnSpanSet;
@@ -2065,6 +2066,8 @@ private: // CLOOK-Impl-methods
 
     ScRefCellValue GetRefCellValue( const ScAddress& rPos );
 
+    svl::StringPool& GetCellStringPool();
+
     std::map< SCTAB, ScSortParam > mSheetSortParams;
 
 };
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 90f0f2b..f5eccae 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -57,6 +57,7 @@
 #include <svl/zforlist.hxx>
 #include <svl/zformat.hxx>
 #include <svl/broadcast.hxx>
+#include "svl/stringpool.hxx"
 #include "editeng/editstat.hxx"
 
 #include <cstdio>
@@ -1601,6 +1602,7 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
 
 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
 {
+    pEditText->NormalizeString(pDocument->GetCellStringPool());
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
     maCells.set(it, nRow, pEditText);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
@@ -1611,6 +1613,7 @@ void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
 
 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
 {
+    pEditText->NormalizeString(pDocument->GetCellStringPool());
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
@@ -1632,24 +1635,9 @@ void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, cons
     // Sadly there is no other way to change the Pool than to
     // "spool" the Object through a corresponding Engine
     EditEngine& rEngine = pDocument->GetEditEngine();
-    if (!rEditText.HasOnlineSpellErrors())
-    {
-        rEngine.SetText(rEditText);
-        SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
-        return;
-    }
-
-    sal_uLong nControl = rEngine.GetControlWord();
-    const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
-    bool bNewControl = (nControl & nSpellControl) != nSpellControl;
-    if (bNewControl)
-        rEngine.SetControlWord(nControl | nSpellControl);
     rEngine.SetText(rEditText);
-    EditTextObject* pData = rEngine.CreateTextObject();
-    if (bNewControl)
-        rEngine.SetControlWord(nControl);
-
-    SetEditText(rBlockPos, nRow, pData);
+    SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
+    return;
 }
 
 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
@@ -1664,24 +1652,9 @@ void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const S
     // Sadly there is no other way to change the Pool than to
     // "spool" the Object through a corresponding Engine
     EditEngine& rEngine = pDocument->GetEditEngine();
-    if (!rEditText.HasOnlineSpellErrors())
-    {
-        rEngine.SetText(rEditText);
-        SetEditText(nRow, rEngine.CreateTextObject());
-        return;
-    }
-
-    sal_uLong nControl = rEngine.GetControlWord();
-    const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
-    bool bNewControl = (nControl & nSpellControl) != nSpellControl;
-    if (bNewControl)
-        rEngine.SetControlWord(nControl | nSpellControl);
     rEngine.SetText(rEditText);
-    EditTextObject* pData = rEngine.CreateTextObject();
-    if (bNewControl)
-        rEngine.SetControlWord(nControl);
-
-    SetEditText(nRow, pData);
+    SetEditText(nRow, rEngine.CreateTextObject());
+    return;
 }
 
 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
@@ -2157,8 +2130,12 @@ void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
     if (!ValidRow(nRow))
         return;
 
+    rtl_uString* pStr = pDocument->GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
-    maCells.set(it, nRow, rStr);
+    maCells.set(it, nRow, OUString(pStr));
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
     CellStorageModified();
 
@@ -2172,8 +2149,12 @@ void ScColumn::SetRawString(
     if (!ValidRow(nRow))
         return;
 
+    rtl_uString* pStr = pDocument->GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
-    rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
+    rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, OUString(pStr));
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
         rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
     CellStorageModified();
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 500bc1b..9f64090 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -118,8 +118,8 @@ private:
 
 // STATIC DATA -----------------------------------------------------------
 
-ScDocument::ScDocument( ScDocumentMode  eMode,
-                        SfxObjectShell* pDocShell ) :
+ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) :
+        mpCellStringPool(new svl::StringPool(ScGlobal::pCharClass)),
         mpUndoManager( NULL ),
         pEditEngine( NULL ),
         pNoteEngine( NULL ),
@@ -600,6 +600,11 @@ ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
     return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row());
 }
 
+svl::StringPool& ScDocument::GetCellStringPool()
+{
+    return *mpCellStringPool;
+}
+
 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
                                 bool bNotes ) const
 {
diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx
index 9998e83..4c9157d 100644
--- a/sc/source/core/data/documentimport.cxx
+++ b/sc/source/core/data/documentimport.cxx
@@ -17,6 +17,8 @@
 #include "mtvelements.hxx"
 #include "tokenarray.hxx"
 
+#include "svl/stringpool.hxx"
+
 struct ScDocumentImportImpl
 {
     ScDocument& mrDoc;
@@ -148,8 +150,12 @@ void ScDocumentImport::setStringCell(const ScAddress& rPos, const OUString& rStr
     if (!pBlockPos)
         return;
 
+    rtl_uString* pStr = mpImpl->mrDoc.GetCellStringPool().intern(rStr);
+    if (!pStr)
+        return;
+
     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
-    pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), rStr);
+    pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), OUString(pStr));
 }
 
 void ScDocumentImport::setEditCell(const ScAddress& rPos, EditTextObject* pEditText)
@@ -164,6 +170,7 @@ void ScDocumentImport::setEditCell(const ScAddress& rPos, EditTextObject* pEditT
     if (!pBlockPos)
         return;
 
+    pEditText->NormalizeString(mpImpl->mrDoc.GetCellStringPool());
     sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
     pBlockPos->miCellPos = rCells.set(pBlockPos->miCellPos, rPos.Row(), pEditText);
 }
commit bc1c67dc8296cff59759ee4abd5ab0cf0632af85
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 21:46:40 2013 -0400

    Add string pool to document.
    
    Change-Id: I7430af7486a2f7a150ed17a0c345aeeb987ec993

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 1e720a8..73d7c1c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -50,6 +50,7 @@
 
 namespace editeng { class SvxBorderLine; }
 namespace formula { struct VectorRefArray; }
+namespace svl { class StringPool; }
 
 namespace sc {
     struct FormulaGroupContext;
@@ -243,6 +244,8 @@ private:
 
     rtl::Reference<ScPoolHelper> xPoolHelper;
 
+    boost::scoped_ptr<svl::StringPool> mpCellStringPool;
+
     SfxUndoManager*     mpUndoManager;
     ScFieldEditEngine*  pEditEngine;                    // uses pEditPool from xPoolHelper
     ScNoteEditEngine*   pNoteEngine;                    // uses pEditPool from xPoolHelper
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 1086bd1..500bc1b 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -35,6 +35,7 @@
 #include <vcl/virdev.hxx>
 #include <comphelper/processfactory.hxx>
 #include <svl/PasswordHelper.hxx>
+#include "svl/stringpool.hxx"
 #include <tools/tenccvt.hxx>
 #include <tools/urlobj.hxx>
 #include <rtl/crc.h>
@@ -439,6 +440,8 @@ ScDocument::~ScDocument()
 
     delete pPreviewFont;
     OSL_POSTCOND( !pAutoNameCache, "AutoNameCache still set in dtor" );
+
+    mpCellStringPool.reset();
 }
 
 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
commit 57bc9f7edf6ec33c7c81c856cf5a51ea41b67932
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 19:11:28 2013 -0400

    A little more test on shared string pool's life cycle management.
    
    Change-Id: Ic676dd875c27ce60a0707903d7f22207764829e0

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 90f4c44..11a52e6 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -36,6 +36,8 @@
 #include "svl/stringpool.hxx"
 #include "unotools/syslocale.hxx"
 
+#include <boost/scoped_ptr.hpp>
+
 #define DEBUG_UNIT_TEST 1
 
 #if DEBUG_UNIT_TEST
@@ -353,6 +355,48 @@ void Test::testStringPoolPurge()
     aPool.purge();
     CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
     CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
+
+    // Now, create string objects on the heap.
+    boost::scoped_ptr<OUString> pStr1(new OUString("Andy"));
+    boost::scoped_ptr<OUString> pStr2(new OUString("andy"));
+    boost::scoped_ptr<OUString> pStr3(new OUString("ANDY"));
+    boost::scoped_ptr<OUString> pStr4(new OUString("Bruce"));
+    aPool.intern(*pStr1);
+    aPool.intern(*pStr2);
+    aPool.intern(*pStr3);
+    aPool.intern(*pStr4);
+
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 4);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // This shouldn't purge anything.
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 4);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Delete one heap string object, and purge. That should purge one string.
+    pStr1.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 3);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Ditto...
+    pStr3.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 2);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 2);
+
+    // Again.
+    pStr2.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 1);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 1);
+
+    // Delete 'Bruce' and purge.
+    pStr4.reset();
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
 }
 
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
commit 00d08001da8dceeb77f16dca523979aa8ccc3755
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 18:54:28 2013 -0400

    No need to intern strings here; all OUString's are ref-counted.
    
    Calling intern() simply moves it to a global hash storage.  Now
    the test passes.
    
    Change-Id: I0a93420abce1c3adaaa61d469dff5f359dd5ada4

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 26cad83..90f4c44 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -75,7 +75,7 @@ public:
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
     CPPUNIT_TEST(testStringPool);
-//  CPPUNIT_TEST(testStringPoolPurge); // FIXME: String pool's life cycle needs more work.
+    CPPUNIT_TEST(testStringPoolPurge);
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index f4d9996..4760348 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -128,7 +128,7 @@ StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const
     if (it == rPool.end())
     {
         // Not yet in the pool.
-        std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr.intern());
+        std::pair<StrHashType::iterator, bool> r = rPool.insert(rStr);
         if (!r.second)
             // Insertion failed.
             return InsertResultType(rPool.end(), false);
commit 5f5876e5c395808006daef3456a961d9e6756791
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 16:35:41 2013 -0400

    Add purge() method to purge unreferenced strings from the pool.
    
    But this code needs more work.
    
    Change-Id: I538eebf5eb1738a2cfeebc22052b3d5db6001b6b

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index d2eca12..cac7637 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -54,7 +54,8 @@ public:
 
     /**
      * Get a unique ID of string object that's expected to be in the shared
-     * string pool. If the string is not in the pool, NULL is returned.
+     * string pool. If the string is not in the pool, NULL is returned.  The
+     * ID obtained by this method can be used for case sensitive comparison.
      *
      * @param rStr string object to get the ID of.
      *
@@ -62,8 +63,27 @@ public:
      */
     StrIdType getIdentifier( const OUString& rStr ) const;
 
+    /**
+     * Get a unique ID of string object for case insensitive comparison. The
+     * string object is expected to be in the pool.
+     *
+     * @param rStr string object to get the ID of.
+     *
+     * @return unique ID of the string object usable for case insensitive
+     *         comparison.
+     */
     StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
 
+    /**
+     * Go through all string objects in the pool, and clear those that are no
+     * longer used outside of the pool.
+     */
+    void purge();
+
+    size_t getCount() const;
+
+    size_t getCountIgnoreCase() const;
+
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
 };
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 58882bb..26cad83 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -36,7 +36,7 @@
 #include "svl/stringpool.hxx"
 #include "unotools/syslocale.hxx"
 
-#define DEBUG_UNIT_TEST 0
+#define DEBUG_UNIT_TEST 1
 
 #if DEBUG_UNIT_TEST
 #include <iostream>
@@ -68,12 +68,14 @@ public:
 
     void testNumberFormat();
     void testStringPool();
+    void testStringPoolPurge();
     void testFdo60915();
     void testI116701();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
     CPPUNIT_TEST(testStringPool);
+//  CPPUNIT_TEST(testStringPoolPurge); // FIXME: String pool's life cycle needs more work.
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
@@ -335,6 +337,24 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_EQUAL(si1, si2);
 }
 
+void Test::testStringPoolPurge()
+{
+    SvtSysLocale aSysLocale;
+    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+    aPool.intern("Andy");
+    aPool.intern("andy");
+    aPool.intern("ANDY");
+
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 3);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 1);
+
+    // Since no string objects referencing the pooled strings exist, purging
+    // the pool should empty it.
+    aPool.purge();
+    CPPUNIT_ASSERT_MESSAGE("Wrong string count.", aPool.getCount() == 0);
+    CPPUNIT_ASSERT_MESSAGE("Wrong case insensitive string count.", aPool.getCountIgnoreCase() == 0);
+}
+
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
                               const OUString& sCode,
                               double fPreviewNumber,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 11b6288..f4d9996 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -67,6 +67,60 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
     return reinterpret_cast<StrIdType>(pUpper);
 }
 
+namespace {
+
+inline sal_Int32 getRefCount( const rtl_uString* p )
+{
+    return (p->refCount & 0x3FFFFFFF);
+}
+
+}
+
+void StringPool::purge()
+{
+    StrHashType aNewStrPool;
+    StrHashType::iterator it = maStrPool.begin(), itEnd = maStrPool.end();
+    for (; it != itEnd; ++it)
+    {
+        const rtl_uString* p = it->pData;
+        if (getRefCount(p) == 1)
+        {
+            // Remove it from the upper string map.  This should unref the
+            // upper string linked to this original string.
+            maToUpperMap.erase(p);
+        }
+        else
+            // Still referenced outside the pool. Keep it.
+            aNewStrPool.insert(*it);
+    }
+
+    maStrPool.swap(aNewStrPool);
+
+    aNewStrPool.clear(); // for re-use.
+
+    // Purge the upper string pool as well.
+    it = maStrPoolUpper.begin();
+    itEnd = maStrPoolUpper.end();
+    for (; it != itEnd; ++it)
+    {
+        const rtl_uString* p = it->pData;
+        if (getRefCount(p) > 1)
+            aNewStrPool.insert(*it);
+    }
+
+    maStrPoolUpper.swap(aNewStrPool);
+}
+
+size_t StringPool::getCount() const
+{
+    return maStrPool.size();
+}
+
+size_t StringPool::getCountIgnoreCase() const
+{
+    return maStrPoolUpper.size();
+}
+
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
 {
     StrHashType::iterator it = rPool.find(rStr);
commit 46ca6ab1fe69a29b75c3b9c3a04af27b5af63fd3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 14:06:13 2013 -0400

    The map actualy needs to store OUString to have it ref-counted automatically.
    
    Change-Id: Iff6fcf3aba73f2d06ac0c885b39e69ac0febc49f

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 4436efe..d2eca12 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -29,7 +29,7 @@ class SVL_DLLPUBLIC StringPool
 {
     typedef boost::unordered_set<OUString, OUStringHash> StrHashType;
     typedef std::pair<StrHashType::iterator, bool> InsertResultType;
-    typedef boost::unordered_map<const rtl_uString*, const rtl_uString*> StrIdMapType;
+    typedef boost::unordered_map<const rtl_uString*, OUString> StrIdMapType;
 
     StrHashType maStrPool;
     StrHashType maStrPoolUpper;
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 76dc4aa..11b6288 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -40,8 +40,7 @@ rtl_uString* StringPool::intern( const OUString& rStr )
         return pOrig;
 
     // Set mapping.
-    rtl_uString* pUpper = aRes.first->pData;
-    maToUpperMap.insert(StrIdMapType::value_type(pOrig, pUpper));
+    maToUpperMap.insert(StrIdMapType::value_type(pOrig, *aRes.first));
 
     return pOrig;
 }
@@ -64,7 +63,7 @@ StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr
         // Passed string is not in the pool.
         return 0;
 
-    const rtl_uString* pUpper = itUpper->second;
+    const rtl_uString* pUpper = itUpper->second.pData;
     return reinterpret_cast<StrIdType>(pUpper);
 }
 
commit 2c96a2887360f3b152b369a745440d4b503aa70d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 13:06:20 2013 -0400

    Correct way to get case-insensitive string identifiers.
    
    Change-Id: Ia343165941231fab34c4904b7a2fa10b07fa32bb

diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 003a152..58882bb 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -307,7 +307,11 @@ void Test::testStringPool()
     OUString aAndy("Andy");
     svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
     svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si1);
+    CPPUNIT_ASSERT_MESSAGE("Identifier shouldn't be 0.", si2);
     CPPUNIT_ASSERT_EQUAL(si1, si2);
+    si1 = aPool.getIdentifierIgnoreCase(aAndy);
+    CPPUNIT_ASSERT_MESSAGE("Case insensitive identifier shouldn't be 0.", si1);
 
     // Test case insensitive string ID's.
     OUString aAndyLower("andy"), aAndyUpper("ANDY");
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index c0030fe..76dc4aa 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -48,18 +48,24 @@ rtl_uString* StringPool::intern( const OUString& rStr )
 
 StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
 {
-    StrHashType::iterator it = maStrPool.find(rStr);
+    StrHashType::const_iterator it = maStrPool.find(rStr);
     return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
 StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
-    if (!mpCharClass)
+    StrHashType::const_iterator itOrig = maStrPool.find(rStr);
+    if (itOrig == maStrPool.end())
+        // Not in the pool.
         return 0;
 
-    OUString aUpper = mpCharClass->uppercase(rStr);
-    StrHashType::iterator it = maStrPoolUpper.find(aUpper);
-    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
+    StrIdMapType::const_iterator itUpper = maToUpperMap.find(itOrig->pData);
+    if (itUpper == maToUpperMap.end())
+        // Passed string is not in the pool.
+        return 0;
+
+    const rtl_uString* pUpper = itUpper->second;
+    return reinterpret_cast<StrIdType>(pUpper);
 }
 
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
commit b3674c9291a09c4e278a0875b691fc7aaf3f38cd
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 12:19:19 2013 -0400

    Let's not expose the internal pointer. Define different ID type.
    
    To prevent the string ID's from being used to instantiate string objects,
    which can mess up shared string object's life cycles.
    
    Change-Id: Ibcd9a4fa9f591d5c27a9e1b50bc9f83ae230e86a

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 26785e3..4436efe 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -37,6 +37,8 @@ class SVL_DLLPUBLIC StringPool
     const CharClass* mpCharClass;
 
 public:
+    typedef sal_uIntPtr StrIdType;
+
     StringPool();
     StringPool( const CharClass* pCharClass );
 
@@ -58,9 +60,9 @@ public:
      *
      * @return unique ID of the string object.
      */
-    const rtl_uString* getIdentifier( const OUString& rStr ) const;
+    StrIdType getIdentifier( const OUString& rStr ) const;
 
-    const rtl_uString* getIdentifierIgnoreCase( const OUString& rStr ) const;
+    StrIdType getIdentifierIgnoreCase( const OUString& rStr ) const;
 
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index f41ab73..003a152 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -305,27 +305,30 @@ void Test::testStringPool()
     CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
 
     OUString aAndy("Andy");
-    p2 = aPool.getIdentifier(aAndy);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
+    svl::StringPool::StrIdType si1 = aPool.getIdentifier("Andy");
+    svl::StringPool::StrIdType si2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
 
     // Test case insensitive string ID's.
     OUString aAndyLower("andy"), aAndyUpper("ANDY");
-    p1 = aPool.getIdentifier("Andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
-    p2 = aPool.intern(aAndyLower);
-    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
-    p2 = aPool.intern(aAndyUpper);
-    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
-
-    p1 = aPool.getIdentifierIgnoreCase("Andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
-    p2 = aPool.getIdentifierIgnoreCase("andy");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
-
-    p2 = aPool.getIdentifierIgnoreCase("ANDY");
-    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
-    CPPUNIT_ASSERT_EQUAL(p1, p2);
+    si1 = aPool.getIdentifier("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si1);
+    aPool.intern(aAndyLower);
+    si2 = aPool.getIdentifier(aAndyLower);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", si1 != si2);
+    aPool.intern(aAndyUpper);
+    si2 = aPool.getIdentifier(aAndyUpper);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", si1 != si2);
+
+    si1 = aPool.getIdentifierIgnoreCase("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si1);
+    si2 = aPool.getIdentifierIgnoreCase("andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si2);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
+
+    si2 = aPool.getIdentifierIgnoreCase("ANDY");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", si2);
+    CPPUNIT_ASSERT_EQUAL(si1, si2);
 }
 
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 1181538..c0030fe 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -46,20 +46,20 @@ rtl_uString* StringPool::intern( const OUString& rStr )
     return pOrig;
 }
 
-const rtl_uString* StringPool::getIdentifier( const OUString& rStr ) const
+StringPool::StrIdType StringPool::getIdentifier( const OUString& rStr ) const
 {
     StrHashType::iterator it = maStrPool.find(rStr);
-    return (it == maStrPool.end()) ? NULL : it->pData;
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
-const rtl_uString* StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+StringPool::StrIdType StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
 {
     if (!mpCharClass)
-        return NULL;
+        return 0;
 
     OUString aUpper = mpCharClass->uppercase(rStr);
     StrHashType::iterator it = maStrPoolUpper.find(aUpper);
-    return (it == maStrPool.end()) ? NULL : it->pData;
+    return (it == maStrPool.end()) ? 0 : reinterpret_cast<StrIdType>(it->pData);
 }
 
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
commit 4d076d4ceeb05061b6b0699c19af9ba5ed0fcd00
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 11:29:42 2013 -0400

    Write some rudimentary tests for the new shared string pool class.
    
    Change-Id: Ie66de46d69f664839aa0a2d056cd3b8df4d4989b

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 2541568..26785e3 100644
--- a/include/svl/stringpool.hxx
+++ b/include/svl/stringpool.hxx
@@ -34,11 +34,11 @@ class SVL_DLLPUBLIC StringPool
     StrHashType maStrPool;
     StrHashType maStrPoolUpper;
     StrIdMapType maToUpperMap;
-    CharClass* mpCharClass;
+    const CharClass* mpCharClass;
 
 public:
     StringPool();
-    StringPool( CharClass* pCharClass );
+    StringPool( const CharClass* pCharClass );
 
     /**
      * Intern a string object into the shared string pool.
@@ -60,6 +60,8 @@ public:
      */
     const rtl_uString* getIdentifier( const OUString& rStr ) const;
 
+    const rtl_uString* getIdentifierIgnoreCase( const OUString& rStr ) const;
+
 private:
     InsertResultType findOrInsert( StrHashType& rPool, const OUString& rStr ) const;
 };
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 8d46ecf..f41ab73 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -33,6 +33,8 @@
 
 #include "svl/zforlist.hxx"
 #include "svl/zformat.hxx"
+#include "svl/stringpool.hxx"
+#include "unotools/syslocale.hxx"
 
 #define DEBUG_UNIT_TEST 0
 
@@ -65,11 +67,13 @@ public:
     virtual void tearDown();
 
     void testNumberFormat();
+    void testStringPool();
     void testFdo60915();
     void testI116701();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testNumberFormat);
+    CPPUNIT_TEST(testStringPool);
     CPPUNIT_TEST(testFdo60915);
     CPPUNIT_TEST(testI116701);
     CPPUNIT_TEST_SUITE_END();
@@ -288,6 +292,42 @@ void Test::testNumberFormat()
     }
 }
 
+void Test::testStringPool()
+{
+    SvtSysLocale aSysLocale;
+    svl::StringPool aPool(aSysLocale.GetCharClassPtr());
+
+    const rtl_uString* p1 = aPool.intern("Andy");
+    const rtl_uString* p2 = aPool.intern("Andy");
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    p2 = aPool.intern("Bruce");
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+
+    OUString aAndy("Andy");
+    p2 = aPool.getIdentifier(aAndy);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    // Test case insensitive string ID's.
+    OUString aAndyLower("andy"), aAndyUpper("ANDY");
+    p1 = aPool.getIdentifier("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
+    p2 = aPool.intern(aAndyLower);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+    p2 = aPool.intern(aAndyUpper);
+    CPPUNIT_ASSERT_MESSAGE("They must differ.", p1 != p2);
+
+    p1 = aPool.getIdentifierIgnoreCase("Andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p1);
+    p2 = aPool.getIdentifierIgnoreCase("andy");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+
+    p2 = aPool.getIdentifierIgnoreCase("ANDY");
+    CPPUNIT_ASSERT_MESSAGE("This shouldn't be NULL.", p2);
+    CPPUNIT_ASSERT_EQUAL(p1, p2);
+}
+
 void Test::checkPreviewString(SvNumberFormatter& aFormatter,
                               const OUString& sCode,
                               double fPreviewNumber,
diff --git a/svl/source/misc/stringpool.cxx b/svl/source/misc/stringpool.cxx
index 46462d1..1181538 100644
--- a/svl/source/misc/stringpool.cxx
+++ b/svl/source/misc/stringpool.cxx
@@ -13,7 +13,7 @@
 namespace svl {
 
 StringPool::StringPool() : mpCharClass(NULL) {}
-StringPool::StringPool( CharClass* pCharClass ) : mpCharClass(pCharClass) {}
+StringPool::StringPool( const CharClass* pCharClass ) : mpCharClass(pCharClass) {}
 
 rtl_uString* StringPool::intern( const OUString& rStr )
 {
@@ -52,6 +52,16 @@ const rtl_uString* StringPool::getIdentifier( const OUString& rStr ) const
     return (it == maStrPool.end()) ? NULL : it->pData;
 }
 
+const rtl_uString* StringPool::getIdentifierIgnoreCase( const OUString& rStr ) const
+{
+    if (!mpCharClass)
+        return NULL;
+
+    OUString aUpper = mpCharClass->uppercase(rStr);
+    StrHashType::iterator it = maStrPoolUpper.find(aUpper);
+    return (it == maStrPool.end()) ? NULL : it->pData;
+}
+
 StringPool::InsertResultType StringPool::findOrInsert( StrHashType& rPool, const OUString& rStr ) const
 {
     StrHashType::iterator it = rPool.find(rStr);
commit 5d3ea0cde3f4c61832c48281e75dabd22621a893
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Oct 2 10:47:28 2013 -0400

    Establish mapping between original strings and upper strings.
    
    This will be used to retrieve case insensitive string identifiers
    later.
    
    Change-Id: Ia34f57d0e8d0cb6bd4630f8d110853ed049770b5

diff --git a/include/svl/stringpool.hxx b/include/svl/stringpool.hxx
index 643c846..2541568 100644

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list