From 816279ecf7d768110a51accda11ce0037e04068c Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Fri, 7 Dec 2012 13:16:23 +0000 Subject: fdo#44736 - convert RTFSprms to a copy-on-write structure. Also try to avoid copy/delete thrash of RTFParserState. --- writerfilter/source/rtftok/rtfdocumentimpl.cxx | 7 ++- writerfilter/source/rtftok/rtfsprm.cxx | 58 ++++++++++++++++------ writerfilter/source/rtftok/rtfsprm.hxx | 67 +++++++++++++++++--------- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index aa90d3b07b7e..78bd1058fa56 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -3407,16 +3407,15 @@ int RTFDocumentImpl::pushState() checkUnicode(); m_nGroupStartPos = Strm().Tell(); - RTFParserState aState(this); + if (m_aStates.empty()) - aState = m_aDefaultState; + m_aStates.push(m_aDefaultState); else { if (m_aStates.top().nDestinationState == DESTINATION_MR) lcl_DestinationToMath(m_aStates.top().aDestinationText, m_aMathBuffer); - aState = m_aStates.top(); + m_aStates.push(m_aStates.top()); } - m_aStates.push(aState); m_aStates.top().aDestinationText.setLength(0); m_pTokenizer->pushGroup(); diff --git a/writerfilter/source/rtftok/rtfsprm.cxx b/writerfilter/source/rtftok/rtfsprm.cxx index 2958cde25cb8..e11dbe6a9f80 100644 --- a/writerfilter/source/rtftok/rtfsprm.cxx +++ b/writerfilter/source/rtftok/rtfsprm.cxx @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Version: MPL 1.1 / GPLv3+ / LGPLv3+ * @@ -99,7 +100,7 @@ std::string RTFSprm::toString() const RTFValue::Pointer_t RTFSprms::find(Id nKeyword) { - for (RTFSprms::Iterator_t i = m_aSprms.begin(); i != m_aSprms.end(); ++i) + for (RTFSprms::Iterator_t i = m_pSprms->begin(); i != m_pSprms->end(); ++i) if (i->first == nKeyword) return i->second; RTFValue::Pointer_t pValue; @@ -108,33 +109,39 @@ RTFValue::Pointer_t RTFSprms::find(Id nKeyword) void RTFSprms::set(Id nKeyword, RTFValue::Pointer_t pValue, bool bOverwrite) { + ensureCopyBeforeWrite(); if (bOverwrite) { - for (RTFSprms::Iterator_t i = m_aSprms.begin(); i != m_aSprms.end(); ++i) + for (RTFSprms::Iterator_t i = m_pSprms->begin(); i != m_pSprms->end(); ++i) if (i->first == nKeyword) { i->second = pValue; return; } } - m_aSprms.push_back(std::make_pair(nKeyword, pValue)); + m_pSprms->push_back(std::make_pair(nKeyword, pValue)); } bool RTFSprms::erase(Id nKeyword) { - for (RTFSprms::Iterator_t i = m_aSprms.begin(); i != m_aSprms.end(); ++i) + ensureCopyBeforeWrite(); + for (RTFSprms::Iterator_t i = m_pSprms->begin(); i != m_pSprms->end(); ++i) + { if (i->first == nKeyword) { - m_aSprms.erase(i); + m_pSprms->erase(i); return true; } + } return false; } void RTFSprms::deduplicate(RTFSprms& rReference) { - RTFSprms::Iterator_t i = m_aSprms.begin(); - while (i != m_aSprms.end()) + ensureCopyBeforeWrite(); + + RTFSprms::Iterator_t i = m_pSprms->begin(); + while (i != m_pSprms->end()) { bool bIgnore = false; if (i->first != NS_rtf::LN_ISTD) @@ -144,33 +151,56 @@ void RTFSprms::deduplicate(RTFSprms& rReference) bIgnore = true; } if (bIgnore) - i = m_aSprms.erase(i); + i = m_pSprms->erase(i); else ++i; } } +void RTFSprms::ensureCopyBeforeWrite() +{ + if (m_pSprms->m_nRefCount > 1) { + boost::intrusive_ptr pClone(new RTFSprmsImpl()); + for (std::vector< std::pair >::const_iterator i = m_pSprms->begin(); i != m_pSprms->end(); ++i) + pClone->push_back(std::make_pair(i->first, RTFValue::Pointer_t(i->second->Clone()))); + m_pSprms = pClone; + assert(m_pSprms->m_nRefCount == 1); + } +} + RTFSprms::RTFSprms() - : m_aSprms() + : m_pSprms(new RTFSprmsImpl()) +{ +} + +RTFSprms::~RTFSprms() { } RTFSprms::RTFSprms(const RTFSprms& rSprms) { - for (std::vector< std::pair >::const_iterator i = rSprms.m_aSprms.begin(); i != rSprms.m_aSprms.end(); ++i) - m_aSprms.push_back(std::make_pair(i->first, RTFValue::Pointer_t(i->second->Clone()))); + *this = rSprms; } RTFSprms& RTFSprms::operator=(const RTFSprms& rOther) { - RTFSprms aTmp(rOther); - swap(aTmp); + m_pSprms = rOther.m_pSprms; return *this; } void RTFSprms::swap(RTFSprms& rOther) { - m_aSprms.swap(rOther.m_aSprms); + boost::intrusive_ptr pTmp = rOther.m_pSprms; + rOther.m_pSprms = m_pSprms; + m_pSprms = pTmp; +} + +void RTFSprms::clear() +{ + if (m_pSprms->m_nRefCount == 1) + return m_pSprms->clear(); + else + m_pSprms.reset(new RTFSprmsImpl()); } } // namespace rtftok diff --git a/writerfilter/source/rtftok/rtfsprm.hxx b/writerfilter/source/rtftok/rtfsprm.hxx index 80d41a3c0f69..5f7a793cb28a 100644 --- a/writerfilter/source/rtftok/rtfsprm.hxx +++ b/writerfilter/source/rtftok/rtfsprm.hxx @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Version: MPL 1.1 / GPLv3+ / LGPLv3+ * @@ -28,36 +29,58 @@ #ifndef _RTFSPRM_HXX_ #define _RTFSPRM_HXX_ +#include #include #include namespace writerfilter { namespace rtftok { + + typedef std::vector< std::pair > RTFSprmsImplBase; + class RTFSprmsImpl : public RTFSprmsImplBase + { + public: + sal_Int32 m_nRefCount; + RTFSprmsImpl() : RTFSprmsImplBase(), m_nRefCount(0) {} + }; + + inline void intrusive_ptr_add_ref(RTFSprmsImpl* p) + { + ++(p->m_nRefCount); + } + inline void intrusive_ptr_release(RTFSprmsImpl* p) + { + if (!--(p->m_nRefCount)) + delete p; + } + /// A list of RTFSprm with a copy constructor that performs a deep copy. class RTFSprms { - public: - typedef ::boost::shared_ptr Pointer_t; - typedef std::pair Entry_t; - typedef std::vector::iterator Iterator_t; - RTFSprms(); - RTFSprms(const RTFSprms& rSprms); - RTFSprms& operator=(const RTFSprms& rOther); - RTFValue::Pointer_t find(Id nKeyword); - /// Does the same as ->push_back(), except that it can overwrite existing entries. - void set(Id nKeyword, RTFValue::Pointer_t pValue, bool bOverwrite = true); - bool erase(Id nKeyword); - /// Removes elements, which are already in the reference set. - void deduplicate(RTFSprms& rReference); - void swap(RTFSprms& rOther); - size_t size() const { return m_aSprms.size(); } - bool empty() const { return m_aSprms.empty(); } - Entry_t& back() { return m_aSprms.back(); } - Iterator_t begin() { return m_aSprms.begin(); } - Iterator_t end() { return m_aSprms.end(); } - void clear() { return m_aSprms.clear(); } - private: - std::vector< std::pair > m_aSprms; + public: + typedef ::boost::shared_ptr Pointer_t; + typedef std::pair Entry_t; + typedef std::vector::iterator Iterator_t; + RTFSprms(); + RTFSprms(const RTFSprms& rSprms); + ~RTFSprms(); + RTFSprms& operator=(const RTFSprms& rOther); + RTFValue::Pointer_t find(Id nKeyword); + /// Does the same as ->push_back(), except that it can overwrite existing entries. + void set(Id nKeyword, RTFValue::Pointer_t pValue, bool bOverwrite = true); + bool erase(Id nKeyword); + /// Removes elements, which are already in the reference set. + void deduplicate(RTFSprms& rReference); + void swap(RTFSprms& rOther); + size_t size() const { return m_pSprms->size(); } + bool empty() const { return m_pSprms->empty(); } + Entry_t& back() { return m_pSprms->back(); } + Iterator_t begin() { return m_pSprms->begin(); } + Iterator_t end() { return m_pSprms->end(); } + void clear(); + private: + void ensureCopyBeforeWrite(); + boost::intrusive_ptr m_pSprms; }; /// RTF keyword with a parameter -- cgit v1.2.3