Files
libreoffice/sw/inc/ring.hxx

273 lines
11 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
re-base on ALv2 code. Includes: Patches contributed by Oliver-Rainer Wittmann sw34bf06: #i117783# - Writer's implementation of XPagePrintable - apply print settings to new printing routines http://svn.apache.org/viewvc?view=revision&revision=1172115 sw34bf06: #o12311627# use <rtl_random> methods to create unique ids for list styles and list ids http://svn.apache.org/viewvc?view=revision&revision=1172112 sw34bf06 #i114725#,#i115828# - method <SwDoc::ClearDoc()> - clear list structures completely http://svn.apache.org/viewvc?view=revision&revision=1172122 i#118572 - remove ui string and help content regarding usage of Java Mail in Writer's Mail Merge as Java Mail is not used. http://svn.apache.org/viewvc?view=revision&revision=1197035 Patches contributed by Mathias Bauer cws mba34issues01: #i117718#: provide filter name in case storage of medium does not allow to detect one http://svn.apache.org/viewvc?view=revision&revision=1172350 cws mba34issues01: #i117721#: directly provide parameters retrieved from SfxMedium http://svn.apache.org/viewvc?view=revision&revision=1172353 gnumake4 work variously http://svn.apache.org/viewvc?view=revision&revision=1394707 http://svn.apache.org/viewvc?view=revision&revision=1394326 http://svn.apache.org/viewvc?view=revision&revision=1396797 http://svn.apache.org/viewvc?view=revision&revision=1397315 cws mba34issues01: #i117723#: convert assertion into trace http://svn.apache.org/viewvc?view=revision&revision=1172355 cws mba34issues01: #i117699#: keep layout alive until swdoc dies http://svn.apache.org/viewvc?view=revision&revision=1172362 cws mba34issues01: #i117943#: missing color attributes in RTF clipboard http://svn.apache.org/viewvc?view=revision&revision=1172363 Patch contributed by Henning Brinkmann imported patch i#103878 http://svn.apache.org/viewvc?view=revision&revision=1172109 Patches contributed by Michael Stahl sw34bf06: #i117955#: WW8 export: disable storing of section breaks in endnotes http://svn.apache.org/viewvc?view=revision&revision=1172119 Patch contributed by imacat Fixed the Asian language work count. http://svn.apache.org/viewvc?view=revision&revision=1241345 Patch contributed by Pedro Giffuni i#20878 - Add comment with BZ issue for reference. http://svn.apache.org/viewvc?view=revision&revision=1244517 Patch contributed by Andre Fischer Do not add targets for junit tests when junit is disabled. http://svn.apache.org/viewvc?view=revision&revision=1241508 add writerperfect dependency.
2011-03-31 10:05:04 +02:00
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifndef INCLUDED_SW_INC_RING_HXX
#define INCLUDED_SW_INC_RING_HXX
2000-09-18 16:15:01 +00:00
2010-11-14 02:05:55 +01:00
#include <swdllapi.h>
#include <swtypes.hxx>
#include <utility>
#include <iterator>
#include <type_traits>
2014-12-01 02:27:14 +01:00
#include <boost/iterator/iterator_facade.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
namespace sw
2000-09-18 16:15:01 +00:00
{
template <typename value_type> class RingContainer;
template <typename value_type> class RingIterator;
/**
* An intrusive container class double linking the contained nodes
* @example sw/qa/core/uwriter.cxx
*/
template <typename value_type>
class Ring
{
public:
typedef typename std::add_const<value_type>::type const_value_type;
typedef RingContainer<value_type> ring_container;
typedef RingContainer<const_value_type> const_ring_container;
virtual ~Ring()
{ unlink(); };
/** algo::unlink is buggy! don't call it directly! */
void unlink()
{
algo::unlink(this);
pNext = this; // don't leave pointers to old list behind!
pPrev = this;
}
/**
* Removes this item from its current ring container and adds it to
* another ring container. If the item was not alone in the original
* ring container, the other items in the ring will stay in the old
* ring container.
* Note: the newly created item will be inserted just before item pDestRing.
* @param pDestRing the container to add this item to
*/
void MoveTo( value_type* pDestRing );
/** @return a stl-like container with begin()/end() for iteration */
ring_container GetRingContainer();
/** @return a stl-like container with begin()/end() for const iteration */
const_ring_container GetRingContainer() const;
2000-09-18 16:15:01 +00:00
protected:
/**
* Creates a new item in a ring container all by itself.
* Note: Ring instances can newer be outside a container. At most, they
* are alone in one.
*/
Ring()
: pNext(this)
, pPrev(this)
{ }
/**
* Creates a new item and add it to an existing ring container.
* Note: the newly created item will be inserted just before item pRing.
* @param pRing ring container to add the created item to
*/
Ring( value_type* pRing );
/** @return the next item in the ring container */
value_type* GetNextInRing()
{ return static_cast<value_type *>(pNext); }
/** @return the previous item in the ring container */
value_type* GetPrevInRing()
{ return static_cast<value_type *>(pPrev); }
/** @return the next item in the ring container */
const_value_type* GetNextInRing() const
{ return static_cast<value_type *>(pNext); }
/** @return the previous item in the ring container */
const_value_type* GetPrevInRing() const
{ return static_cast<value_type *>(pPrev); }
/** @return true if and only if this item is alone in its ring */
bool unique() const
{ return algo::unique(static_cast< const_value_type* >(this)); }
private:
/** internal implementation class -- not for external use */
struct Ring_node_traits
{
typedef Ring node;
typedef Ring* node_ptr;
typedef const Ring* const_node_ptr;
static node_ptr get_next(const_node_ptr n) { return const_cast<node_ptr>(n)->pNext; };
static void set_next(node_ptr n, node_ptr next) { n->pNext = next; };
static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->pPrev; };
static void set_previous(node_ptr n, node_ptr previous) { n->pPrev = previous; };
};
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)
// gcc 4.6 backwards compat hack, remove ASAP when we drop support
template<typename gcc_hack_value> friend class sw::RingContainer;
template<typename gcc_hack_value> friend class sw::RingIterator;
#else
friend ring_container;
friend const_ring_container;
friend typename ring_container::iterator;
friend typename ring_container::const_iterator;
friend typename const_ring_container::iterator;
friend typename const_ring_container::const_iterator;
#endif
friend class boost::iterator_core_access;
typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
Ring* pNext;
Ring* pPrev;
};
template <typename value_type>
inline Ring<value_type>::Ring( value_type* pObj )
: pNext(this)
, pPrev(this)
{
if( pObj )
{
algo::link_before(pObj, this);
}
}
template <typename value_type>
inline void Ring<value_type>::MoveTo(value_type* pDestRing)
{
value_type* pThis = static_cast< value_type* >(this);
unlink();
// insert into "new"
if (pDestRing)
2014-12-01 02:27:14 +01:00
{
algo::link_before(pDestRing, pThis);
2014-12-01 02:27:14 +01:00
}
}
2014-12-01 02:27:14 +01:00
/**
* helper class that provides Svalue_typeL-style container iteration to the ring
*/
template <typename value_type>
class RingContainer SAL_FINAL
{
private:
/** the item in the ring where iteration starts */
value_type* m_pStart;
typedef typename std::remove_const<value_type>::type nonconst_value_type;
public:
RingContainer( value_type* pRing ) : m_pStart(pRing) {};
typedef RingIterator<value_type> iterator;
typedef RingIterator<const value_type> const_iterator;
/**
* iterator access
* @code
* for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
* do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
* @endcode
*/
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
/** @return the number of elements in the container */
size_t size() const
{ return std::distance(begin(), end()); }
/**
* Merges two ring containers. All item from both ring containers will
* be in the same ring container in the end.
* Note: The items of this ring container will be inserted just before
* item pDestRing
* @param pDestRing the container to merge this container with
*/
void merge( RingContainer< value_type > aDestRing )
{
// first check that we aren't merged already, swapping would
// actually un-merge in this case!
assert(m_pStart->pPrev != aDestRing.m_pStart);
assert(m_pStart != aDestRing.m_pStart->pPrev);
std::swap(*(&m_pStart->pPrev->pNext), *(&aDestRing.m_pStart->pPrev->pNext));
std::swap(*(&m_pStart->pPrev), *(&aDestRing.m_pStart->pPrev));
}
};
template <typename value_type>
class RingIterator SAL_FINAL : public boost::iterator_facade<
RingIterator<value_type>
, value_type
, boost::forward_traversal_tag
>
{
private:
typedef typename std::remove_const<value_type>::type nonconst_value_type;
public:
RingIterator()
: m_pCurrent(nullptr)
, m_pStart(nullptr)
{}
explicit RingIterator(nonconst_value_type* pRing, bool bStart = true)
: m_pCurrent(nullptr)
, m_pStart(pRing)
{
if(!bStart)
m_pCurrent = m_pStart;
}
private:
friend class boost::iterator_core_access;
void increment()
2014-12-19 02:05:44 +01:00
{ m_pCurrent = m_pCurrent ? m_pCurrent->GetNextInRing() : m_pStart->GetNextInRing(); }
bool equal(RingIterator const& other) const
{
// we never want to compare iterators from
// different rings or starting points
assert(m_pStart == other.m_pStart);
return m_pCurrent == other.m_pCurrent;
}
value_type& dereference() const
{ return m_pCurrent ? *m_pCurrent : * m_pStart; }
/**
* value_type is is:
* - pointing to the current item in the iteration in general
* - nullptr if on the first item (begin())
* - m_pStart when beyond the last item (end())
*/
nonconst_value_type* m_pCurrent;
/** the first item of the iteration */
nonconst_value_type* m_pStart;
};
template <typename value_type>
inline typename Ring<value_type>::ring_container Ring<value_type>::GetRingContainer()
{ return Ring<value_type>::ring_container(static_cast< value_type* >(this)); };
template <typename value_type>
inline typename Ring<value_type>::const_ring_container Ring<value_type>::GetRingContainer() const
{ return Ring<value_type>::const_ring_container(static_cast< const_value_type* >(this)); };
template <typename value_type>
inline typename RingContainer<value_type>::iterator RingContainer<value_type>::begin()
{ return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart)); };
template <typename value_type>
inline typename RingContainer<value_type>::iterator RingContainer<value_type>::end()
{ return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
template <typename value_type>
inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::begin() const
{ return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart)); };
template <typename value_type>
inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::end() const
{ return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
}
2000-09-18 16:15:01 +00:00
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */