LCOV - code coverage report
Current view: top level - sw/inc - ring.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 63 63 100.0 %
Date: 2015-06-13 12:38:46 Functions: 120 133 90.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : #ifndef INCLUDED_SW_INC_RING_HXX
      20             : #define INCLUDED_SW_INC_RING_HXX
      21             : 
      22             : #include <swdllapi.h>
      23             : #include <swtypes.hxx>
      24             : #include <utility>
      25             : #include <iterator>
      26             : #include <type_traits>
      27             : #include <boost/iterator/iterator_facade.hpp>
      28             : #include <boost/intrusive/circular_list_algorithms.hpp>
      29             : 
      30             : namespace sw
      31             : {
      32             :     template <typename value_type> class RingContainer;
      33             :     template <typename value_type> class RingIterator;
      34             :     /**
      35             :      * An intrusive container class double linking the contained nodes
      36             :      * @example sw/qa/core/uwriter.cxx
      37             :      */
      38             :     template <typename value_type>
      39             :     class Ring
      40             :     {
      41             :         public:
      42             :             typedef typename std::add_const<value_type>::type const_value_type;
      43             :             typedef RingContainer<value_type> ring_container;
      44             :             typedef RingContainer<const_value_type> const_ring_container;
      45    79318026 :             virtual ~Ring()
      46    79318026 :                 { unlink(); };
      47             :             /** algo::unlink is buggy! don't call it directly! */
      48   212739948 :             void unlink()
      49             :             {
      50   212739948 :                 algo::unlink(this);
      51   212739948 :                 pNext = this; // don't leave pointers to old list behind!
      52   212739948 :                 pPrev = this;
      53   212739948 :             }
      54             :             /**
      55             :              * Removes this item from its current ring container and adds it to
      56             :              * another ring container. If the item was not alone in the original
      57             :              * ring container, the other items in the ring will stay in the old
      58             :              * ring container.
      59             :              * Note: the newly created item will be inserted just before item pDestRing.
      60             :              * @param pDestRing the container to add this item to
      61             :              */
      62             :             void MoveTo( value_type* pDestRing );
      63             :             /** @return a stl-like container with begin()/end() for iteration */
      64             :             ring_container GetRingContainer();
      65             :             /** @return a stl-like container with begin()/end() for const iteration */
      66             :             const_ring_container GetRingContainer() const;
      67             : 
      68             :         protected:
      69             :             /**
      70             :              * Creates a new item in a ring container all by itself.
      71             :              * Note: Ring instances can newer be outside a container. At most, they
      72             :              * are alone in one.
      73             :              */
      74    66714020 :             Ring()
      75             :                 : pNext(this)
      76    66714020 :                 , pPrev(this)
      77    66714020 :                 { }
      78             :             /**
      79             :              * Creates a new item and add it to an existing ring container.
      80             :              * Note: the newly created item will be inserted just before item pRing.
      81             :              * @param pRing ring container to add the created item to
      82             :              */
      83             :             Ring( value_type* pRing );
      84             :             /** @return the next item in the ring container */
      85   138466918 :             value_type* GetNextInRing()
      86   138466918 :                 { return static_cast<value_type *>(pNext); }
      87             :             /** @return the previous item in the ring container */
      88         140 :             value_type* GetPrevInRing()
      89         140 :                 { return static_cast<value_type *>(pPrev); }
      90             :             /** @return the next item in the ring container */
      91         153 :             const_value_type* GetNextInRing() const
      92         153 :                 { return static_cast<value_type *>(pNext); }
      93             :             /** @return the previous item in the ring container */
      94             :             const_value_type* GetPrevInRing() const
      95             :                 { return static_cast<value_type *>(pPrev); }
      96             :             /** @return true if and only if this item is alone in its ring */
      97    61439696 :             bool unique() const
      98    61439696 :                 { return algo::unique(static_cast< const_value_type* >(this)); }
      99             : 
     100             :         private:
     101             :             /** internal implementation class -- not for external use */
     102             :             struct Ring_node_traits
     103             :             {
     104             :                 typedef Ring node;
     105             :                 typedef Ring* node_ptr;
     106             :                 typedef const Ring* const_node_ptr;
     107   274179644 :                 static node_ptr get_next(const_node_ptr n) { return const_cast<node_ptr>(n)->pNext; };
     108   341708046 :                 static void set_next(node_ptr n, node_ptr next) { n->pNext = next; };
     109   277223997 :                 static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->pPrev; };
     110   341708046 :                 static void set_previous(node_ptr n, node_ptr previous) { n->pPrev = previous; };
     111             :             };
     112             : #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)
     113             :             // gcc 4.6 backwards compat hack, remove ASAP when we drop support
     114             :             template<typename gcc_hack_value> friend class sw::RingContainer;
     115             :             template<typename gcc_hack_value> friend class sw::RingIterator;
     116             : #else
     117             :             friend ring_container;
     118             :             friend const_ring_container;
     119             :             friend typename ring_container::iterator;
     120             :             friend typename ring_container::const_iterator;
     121             :             friend typename const_ring_container::iterator;
     122             :             friend typename const_ring_container::const_iterator;
     123             : #endif
     124             :             friend class boost::iterator_core_access;
     125             :             typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
     126             :             Ring* pNext;
     127             :             Ring* pPrev;
     128             :     };
     129             : 
     130             :     template <typename value_type>
     131    12604186 :     inline Ring<value_type>::Ring( value_type* pObj )
     132             :         : pNext(this)
     133    12604186 :         , pPrev(this)
     134             :     {
     135    12604186 :         if( pObj )
     136             :         {
     137         822 :             algo::link_before(pObj, this);
     138             :         }
     139    12604186 :     }
     140             : 
     141             :     template <typename value_type>
     142   133421922 :     inline void Ring<value_type>::MoveTo(value_type* pDestRing)
     143             :     {
     144   133421922 :         value_type* pThis = static_cast< value_type* >(this);
     145   133421922 :         unlink();
     146             :         // insert into "new"
     147   133421922 :         if (pDestRing)
     148             :         {
     149    64483227 :             algo::link_before(pDestRing, pThis);
     150             :         }
     151   133421922 :     }
     152             : 
     153             :     /**
     154             :      * helper class that provides Svalue_typeL-style container iteration to the ring
     155             :      */
     156             :     template <typename value_type>
     157             :     class RingContainer SAL_FINAL
     158             :     {
     159             :         private:
     160             :             /** the item in the ring where iteration starts */
     161             :             value_type* m_pStart;
     162             :             typedef typename std::remove_const<value_type>::type nonconst_value_type;
     163             : 
     164             :         public:
     165   135806575 :             RingContainer( value_type* pRing ) : m_pStart(pRing) {};
     166             :             typedef RingIterator<value_type> iterator;
     167             :             typedef RingIterator<const value_type> const_iterator;
     168             :             /**
     169             :              * iterator access
     170             :              * @code
     171             :              * for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
     172             :              *     do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
     173             :              * @endcode
     174             :              */
     175             :             iterator begin();
     176             :             iterator end();
     177             :             const_iterator begin() const;
     178             :             const_iterator end() const;
     179             :             /** @return the number of elements in the container */
     180          10 :             size_t size() const
     181          10 :                 { return std::distance(begin(), end()); }
     182             :             /**
     183             :              * Merges two ring containers. All item from both ring containers will
     184             :              * be in the same ring container in the end.
     185             :              * Note: The items of this ring container will be inserted just before
     186             :              * item pDestRing
     187             :              * @param pDestRing the container to merge this container with
     188             :              */
     189           2 :             void merge( RingContainer< value_type > aDestRing )
     190             :             {
     191             :                 // first check that we aren't merged already, swapping would
     192             :                 // actually un-merge in this case!
     193             :                 assert(m_pStart->pPrev != aDestRing.m_pStart);
     194             :                 assert(m_pStart != aDestRing.m_pStart->pPrev);
     195           2 :                 std::swap(*(&m_pStart->pPrev->pNext), *(&aDestRing.m_pStart->pPrev->pNext));
     196           2 :                 std::swap(*(&m_pStart->pPrev), *(&aDestRing.m_pStart->pPrev));
     197           2 :             }
     198             :     };
     199             : 
     200             :     template <typename value_type>
     201             :     class RingIterator SAL_FINAL : public boost::iterator_facade<
     202             :           RingIterator<value_type>
     203             :         , value_type
     204             :         , boost::forward_traversal_tag
     205             :         >
     206             :     {
     207             :         private:
     208             :             typedef typename std::remove_const<value_type>::type nonconst_value_type;
     209             :         public:
     210             :             RingIterator()
     211             :                 : m_pCurrent(nullptr)
     212             :                 , m_pStart(nullptr)
     213             :             {}
     214   271613142 :             explicit RingIterator(nonconst_value_type* pRing, bool bStart = true)
     215             :                 : m_pCurrent(nullptr)
     216   271613142 :                 , m_pStart(pRing)
     217             :             {
     218   271613142 :                 if(!bStart)
     219   135806571 :                     m_pCurrent = m_pStart;
     220   271613142 :             }
     221             : 
     222             :         private:
     223             :             friend class boost::iterator_core_access;
     224   137482767 :             void increment()
     225   137482767 :                 { m_pCurrent = m_pCurrent ? m_pCurrent->GetNextInRing() : m_pStart->GetNextInRing(); }
     226   273289338 :             bool equal(RingIterator const& other) const
     227             :             {
     228             :                 // we never want to compare iterators from
     229             :                 // different rings or starting points
     230             :                 assert(m_pStart == other.m_pStart);
     231   273289338 :                 return m_pCurrent == other.m_pCurrent;
     232             :             }
     233   137513208 :             value_type& dereference() const
     234   137513208 :                 { return m_pCurrent ? *m_pCurrent : * m_pStart; }
     235             :             /**
     236             :              * value_type is is:
     237             :              * - pointing to the current item in the iteration in general
     238             :              * - nullptr if on the first item (begin())
     239             :              * - m_pStart when beyond the last item (end())
     240             :              */
     241             :             nonconst_value_type* m_pCurrent;
     242             :             /** the first item of the iteration */
     243             :             nonconst_value_type* m_pStart;
     244             :     };
     245             : 
     246             :     template <typename value_type>
     247   135797718 :     inline typename Ring<value_type>::ring_container Ring<value_type>::GetRingContainer()
     248   135797718 :         { return Ring<value_type>::ring_container(static_cast< value_type* >(this)); };
     249             : 
     250             :     template <typename value_type>
     251        8857 :     inline typename Ring<value_type>::const_ring_container Ring<value_type>::GetRingContainer() const
     252        8857 :         { return Ring<value_type>::const_ring_container(static_cast< const_value_type* >(this)); };
     253             : 
     254             :     template <typename value_type>
     255   135806561 :     inline typename RingContainer<value_type>::iterator RingContainer<value_type>::begin()
     256   135806561 :         { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart)); };
     257             : 
     258             :     template <typename value_type>
     259   135806561 :     inline typename RingContainer<value_type>::iterator RingContainer<value_type>::end()
     260   135806561 :         { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
     261             : 
     262             :     template <typename value_type>
     263          10 :     inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::begin() const
     264          10 :         { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart)); };
     265             : 
     266             :     template <typename value_type>
     267          10 :     inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::end() const
     268          10 :         { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
     269             : }
     270             : #endif
     271             : 
     272             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11