summaryrefslogtreecommitdiffstats
path: root/sw/inc/ring.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/inc/ring.hxx')
-rw-r--r--sw/inc/ring.hxx265
1 files changed, 265 insertions, 0 deletions
diff --git a/sw/inc/ring.hxx b/sw/inc/ring.hxx
new file mode 100644
index 000000000..e152899ec
--- /dev/null
+++ b/sw/inc/ring.hxx
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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
+
+#include <utility>
+#include <sal/types.h>
+#include <iterator>
+#include <type_traits>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/intrusive/circular_list_algorithms.hpp>
+
+namespace sw
+{
+ 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 SAL_WARN_UNUSED 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() COVERITY_NOEXCEPT_FALSE
+ { unlink(); };
+ /** algo::unlink is buggy! don't call it directly! */
+ void unlink()
+ {
+ algo::unlink(this);
+ m_pNext = this; // don't leave pointers to old list behind!
+ m_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;
+
+ 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()
+ : m_pNext(this)
+ , m_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 *>(m_pNext); }
+ /** @return the previous item in the ring container */
+ value_type* GetPrevInRing()
+ { return static_cast<value_type *>(m_pPrev); }
+ /** @return the next item in the ring container */
+ const_value_type* GetNextInRing() const
+ { return static_cast<value_type *>(m_pNext); }
+ /** @return the previous item in the ring container */
+ const_value_type* GetPrevInRing() const
+ { return static_cast<value_type *>(m_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)->m_pNext; };
+ static void set_next(node_ptr n, node_ptr next) { n->m_pNext = next; };
+ static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pPrev; };
+ static void set_previous(node_ptr n, node_ptr previous) { n->m_pPrev = previous; };
+ };
+ 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;
+ friend class boost::iterator_core_access;
+ typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
+ Ring* m_pNext;
+ Ring* m_pPrev;
+ };
+
+ template <typename value_type>
+ inline Ring<value_type>::Ring( value_type* pObj )
+ : m_pNext(this)
+ , m_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)
+ {
+ algo::link_before(pDestRing, pThis);
+ }
+ }
+
+ /**
+ * helper class that provides Svalue_typeL-style container iteration to the ring
+ */
+ template <typename value_type>
+ class SAL_WARN_UNUSED RingContainer 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->m_pPrev != aDestRing.m_pStart);
+ assert(m_pStart != aDestRing.m_pStart->m_pPrev);
+ std::swap(m_pStart->m_pPrev->m_pNext, aDestRing.m_pStart->m_pPrev->m_pNext);
+ std::swap(m_pStart->m_pPrev, aDestRing.m_pStart->m_pPrev);
+ }
+ };
+
+ template <typename value_type>
+ class RingIterator 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()
+ { 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:
+ * - 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); };
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */