1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_SW_INC_RING_HXX
20 #define INCLUDED_SW_INC_RING_HXX
23 #include <swtypes.hxx>
26 #include <type_traits>
27 #include <boost/iterator/iterator_facade.hpp>
28 #include <boost/intrusive/circular_list_algorithms.hpp>
32 template <typename value_type
> class RingContainer
;
33 template <typename value_type
> class RingIterator
;
35 * An intrusive container class double linking the contained nodes
36 * @example sw/qa/core/uwriter.cxx
38 template <typename value_type
>
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
;
47 /** algo::unlink is buggy! don't call it directly! */
51 pNext
= this; // don't leave pointers to old list behind!
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
59 * Note: the newly created item will be inserted just before item pDestRing.
60 * @param pDestRing the container to add this item to
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;
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
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
83 Ring( value_type
* pRing
);
84 /** @return the next item in the ring container */
85 value_type
* GetNextInRing()
86 { return static_cast<value_type
*>(pNext
); }
87 /** @return the previous item in the ring container */
88 value_type
* GetPrevInRing()
89 { return static_cast<value_type
*>(pPrev
); }
90 /** @return the next item in the ring container */
91 const_value_type
* GetNextInRing() const
92 { 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 */
98 { return algo::unique(static_cast< const_value_type
* >(this)); }
101 /** internal implementation class -- not for external use */
102 struct Ring_node_traits
105 typedef Ring
* node_ptr
;
106 typedef const Ring
* const_node_ptr
;
107 static node_ptr
get_next(const_node_ptr n
) { return const_cast<node_ptr
>(n
)->pNext
; };
108 static void set_next(node_ptr n
, node_ptr next
) { n
->pNext
= next
; };
109 static node_ptr
get_previous(const_node_ptr n
) { return const_cast<node_ptr
>(n
)->pPrev
; };
110 static void set_previous(node_ptr n
, node_ptr previous
) { n
->pPrev
= previous
; };
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
;
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
;
124 friend class boost::iterator_core_access
;
125 typedef boost::intrusive::circular_list_algorithms
<Ring_node_traits
> algo
;
130 template <typename value_type
>
131 inline Ring
<value_type
>::Ring( value_type
* pObj
)
137 algo::link_before(pObj
, this);
141 template <typename value_type
>
142 inline void Ring
<value_type
>::MoveTo(value_type
* pDestRing
)
144 value_type
* pThis
= static_cast< value_type
* >(this);
149 algo::link_before(pDestRing
, pThis
);
154 * helper class that provides Svalue_typeL-style container iteration to the ring
156 template <typename value_type
>
157 class RingContainer SAL_FINAL
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
;
165 RingContainer( value_type
* pRing
) : m_pStart(pRing
) {};
166 typedef RingIterator
<value_type
> iterator
;
167 typedef RingIterator
<const value_type
> const_iterator
;
171 * for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
172 * do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
177 const_iterator
begin() const;
178 const_iterator
end() const;
179 /** @return the number of elements in the container */
181 { return std::distance(begin(), end()); }
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
187 * @param pDestRing the container to merge this container with
189 void merge( RingContainer
< value_type
> aDestRing
)
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 std::swap(*(&m_pStart
->pPrev
->pNext
), *(&aDestRing
.m_pStart
->pPrev
->pNext
));
196 std::swap(*(&m_pStart
->pPrev
), *(&aDestRing
.m_pStart
->pPrev
));
200 template <typename value_type
>
201 class RingIterator SAL_FINAL
: public boost::iterator_facade
<
202 RingIterator
<value_type
>
204 , boost::forward_traversal_tag
208 typedef typename
std::remove_const
<value_type
>::type nonconst_value_type
;
211 : m_pCurrent(nullptr)
214 explicit RingIterator(nonconst_value_type
* pRing
, bool bStart
= true)
215 : m_pCurrent(nullptr)
219 m_pCurrent
= m_pStart
;
223 friend class boost::iterator_core_access
;
225 { m_pCurrent
= m_pCurrent
? m_pCurrent
->GetNextInRing() : m_pStart
->GetNextInRing(); }
226 bool equal(RingIterator
const& other
) const
228 // we never want to compare iterators from
229 // different rings or starting points
230 assert(m_pStart
== other
.m_pStart
);
231 return m_pCurrent
== other
.m_pCurrent
;
233 value_type
& dereference() const
234 { return m_pCurrent
? *m_pCurrent
: * m_pStart
; }
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())
241 nonconst_value_type
* m_pCurrent
;
242 /** the first item of the iteration */
243 nonconst_value_type
* m_pStart
;
246 template <typename value_type
>
247 inline typename Ring
<value_type
>::ring_container Ring
<value_type
>::GetRingContainer()
248 { return Ring
<value_type
>::ring_container(static_cast< value_type
* >(this)); };
250 template <typename value_type
>
251 inline typename Ring
<value_type
>::const_ring_container Ring
<value_type
>::GetRingContainer() const
252 { return Ring
<value_type
>::const_ring_container(static_cast< const_value_type
* >(this)); };
254 template <typename value_type
>
255 inline typename RingContainer
<value_type
>::iterator RingContainer
<value_type
>::begin()
256 { return RingContainer
<value_type
>::iterator(const_cast< nonconst_value_type
* >(m_pStart
)); };
258 template <typename value_type
>
259 inline typename RingContainer
<value_type
>::iterator RingContainer
<value_type
>::end()
260 { return RingContainer
<value_type
>::iterator(const_cast< nonconst_value_type
* >(m_pStart
), false); };
262 template <typename value_type
>
263 inline typename RingContainer
<value_type
>::const_iterator RingContainer
<value_type
>::begin() const
264 { return RingContainer
<value_type
>::const_iterator(const_cast< nonconst_value_type
* >(m_pStart
)); };
266 template <typename value_type
>
267 inline typename RingContainer
<value_type
>::const_iterator RingContainer
<value_type
>::end() const
268 { return RingContainer
<value_type
>::const_iterator(const_cast< nonconst_value_type
* >(m_pStart
), false); };
272 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */