BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslalg_bidirectionallinklistutil.h
Go to the documentation of this file.
1/// @file bslalg_bidirectionallinklistutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslalg_bidirectionallinklistutil.h -*-C++-*-
8#ifndef INCLUDED_BSLALG_BIDIRECTIONALLINKLISTUTIL
9#define INCLUDED_BSLALG_BIDIRECTIONALLINKLISTUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslalg_bidirectionallinklistutil bslalg_bidirectionallinklistutil
15/// @brief Provide utilities to maintain bidirectional list data structures.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslalg
19/// @{
20/// @addtogroup bslalg_bidirectionallinklistutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslalg_bidirectionallinklistutil-purpose"> Purpose</a>
25/// * <a href="#bslalg_bidirectionallinklistutil-classes"> Classes </a>
26/// * <a href="#bslalg_bidirectionallinklistutil-description"> Description </a>
27/// * <a href="#bslalg_bidirectionallinklistutil-usage"> Usage </a>
28/// * <a href="#bslalg_bidirectionallinklistutil-example-1-creating-and-using-a-list-template-class"> Example 1: Creating and Using a List Template Class </a>
29///
30/// # Purpose {#bslalg_bidirectionallinklistutil-purpose}
31/// Provide utilities to maintain bidirectional list data structures.
32///
33/// # Classes {#bslalg_bidirectionallinklistutil-classes}
34///
35/// - bslalg::BidirectionalLinkListUtil: utilities to maintain linked lists
36///
37/// @see bslalg_bidirectionallink, bslalg_hashtableimputil
38///
39/// # Description {#bslalg_bidirectionallinklistutil-description}
40/// This component provides a namespace,
41/// `bslalg::BidirectionalLinkListUtil`, containing utility functions for
42/// operating on doubly linked lists with nodes of type
43/// `bslalg::BidirectionalLink`. The operations assume that the linked lists
44/// are either 0 terminated (on both ends) or terminate with sentinel (valid)
45/// nodes. The main operations include insertion and removal of a node from a
46/// list of nodes, and the *splicing* of ranges from one list into another one.
47/// Splicing is the operation of moving a sub-list, or range, of elements from
48/// one linked list and into a second list, at a specified position.
49///
50/// ## Usage {#bslalg_bidirectionallinklistutil-usage}
51///
52///
53/// This section illustrates intended usage of this component.
54///
55/// ### Example 1: Creating and Using a List Template Class {#bslalg_bidirectionallinklistutil-example-1-creating-and-using-a-list-template-class}
56///
57///
58/// First, since `Link` neither has a constructor nor is a POD (which would make
59/// aggregate initialization possible), we create a function `makeLink` to
60/// assemble a link from two pointers:
61/// @code
62/// Link makeLink(Link *prev, Link *next)
63/// {
64/// Link result;
65/// result.setPreviousLink(prev);
66/// result.setNextLink( next);
67///
68/// return result;
69/// }
70/// @endcode
71/// Then, we create a function that will, passed two links that are endpoints
72/// of a linked list from the specified `first` to `last` though the `nextLink`
73/// pointers, count the number of nodes in the list including both endpoints.
74/// @code
75/// int length(Link *first, Link *last)
76/// {
77/// int result = 0;
78/// Link *p = first;
79/// while (p && ++result && last != p) {
80/// p = p->nextLink();
81/// }
82///
83/// return result;
84/// }
85/// @endcode
86/// Next, in our `main`, we declare a `typedef` for the component name and a
87/// a constant `invalid` garbage pointer we use when we want data to be garbage.
88/// @code
89/// typedef BidirectionalLinkListUtil Util;
90/// Link * const invalid = (Link *) 0XBADDEED5;
91/// @endcode
92/// Then, we create a linked list of links and use `isWellFormed` to verify
93/// that it is well formed, and call the `length` method we just created to
94/// verify its length.
95/// @code
96/// Link usageData[] = {
97/// makeLink(0, &usageData[1]),
98/// makeLink(&usageData[0], &usageData[2]),
99/// makeLink(&usageData[1], &usageData[3]),
100/// makeLink(&usageData[2], 0 ) };
101///
102/// assert(Util::isWellFormed( &usageData[0], &usageData[3]));
103/// assert(4 == length(&usageData[0], &usageData[3]));
104/// @endcode
105/// Next, we create two new links `front` and `back`, and initialize them with
106/// garbage:
107/// @code
108/// Link front = makeLink(invalid, invalid);
109/// Link back = makeLink(invalid, invalid);
110/// @endcode
111/// Then, we use our component's `insertLinkBeforeTarget` and
112/// `insertLinkAfterTarget` to concatenate `front` to the front of the list and
113/// `back` to its rear:
114/// @code
115/// Util::insertLinkBeforeTarget(&front, &usageData[0]);
116/// Util::insertLinkAfterTarget( &back, &usageData[3]);
117/// @endcode
118/// Next, We examine the new list and verify we now have a well-formed list, 2
119/// longer than the old list:
120/// @code
121/// assert(0 == front.previousLink());
122/// assert(0 == back .nextLink());
123/// assert(Util::isWellFormed( &front, &back));
124/// assert(6 == length(&front, &back));
125/// @endcode
126/// Then, we use our component's `unlink` method to remove two nodes from our
127/// list. Note that the state of the removed nodes is undefined:
128/// @code
129/// Util::unlink(&usageData[1]);
130/// Util::unlink(&usageData[3]);
131/// @endcode
132/// Next, we verify that the new list is well formed and 2 elements shorter than
133/// it was before we removed those two nodes:
134/// @code
135/// assert(Util::isWellFormed(&front, &back));
136/// assert(4 == length(&front, &back));
137/// @endcode
138/// Then, we weave the two discarded nodes into a new, second list of two nodes,
139/// and use `isWellFormed` and `length` to verify it is as we expect:
140/// @code
141/// usageData[1] = makeLink(0, &usageData[3]);
142/// usageData[3] = makeLink(&usageData[1], 0);
143/// assert(Util::isWellFormed(&usageData[1], &usageData[3]));
144/// assert(2 == length(&usageData[1], &usageData[3]));
145/// @endcode
146/// Next, we use our component's `spliceListBeforeTarget` method to remove the
147/// middle nodes from the longer list and append them to the end of shorter
148/// list. Note that the splicing function not only adds the sequence to the new
149/// list, it also splices the list the sequence is removed from so that both are
150/// well-formed lists:
151/// @code
152/// Util::spliceListBeforeTarget(&usageData[0],
153/// &usageData[2],
154/// &usageData[3]);
155/// @endcode
156/// Then, we use `isWellFormed` and `length` to verify the state of our two
157/// lists:
158/// @code
159/// assert(Util::isWellFormed(&usageData[1], &usageData[3]));
160/// assert(4 == length(&usageData[1], &usageData[3]));
161///
162/// assert(Util::isWellFormed(&front, &back));
163/// assert(2 == length(&front, &back));
164/// @endcode
165/// Next, we call `spliceListBeforeTarget` again to join our two lists into one:
166/// @code
167/// Util::spliceListBeforeTarget(&usageData[1],
168/// &usageData[3],
169/// &back);
170/// @endcode
171/// Now, we use `isWellFormed` and `length` to verify the state of our one
172/// remaining list:
173/// @code
174/// assert(Util::isWellFormed(&front, &back));
175/// assert(6 == length(&front, &back));
176/// assert(0 == front.previousLink());
177/// assert(0 == back .nextLink());
178/// @endcode
179/// Finally, we traverse our list in both directions, examining each node to
180/// verify all the links and that the sequence is as expected:
181/// @code
182/// Link *p = &front;
183/// assert(0 == p->previousLink());
184/// p = p->nextLink();
185/// assert(&usageData[1] == p);
186/// p = p->nextLink();
187/// assert(&usageData[0] == p);
188/// p = p->nextLink();
189/// assert(&usageData[2] == p);
190/// p = p->nextLink();
191/// assert(&usageData[3] == p);
192/// p = p->nextLink();
193/// assert(&back == p);
194/// assert(0 == p->nextLink());
195///
196/// p = p->previousLink();
197/// assert(&usageData[3] == p);
198/// p = p->previousLink();
199/// assert(&usageData[2] == p);
200/// p = p->previousLink();
201/// assert(&usageData[0] == p);
202/// p = p->previousLink();
203/// assert(&usageData[1] == p);
204/// p = p->previousLink();
205/// assert(&front == p);
206/// assert(0 == p->previousLink());
207/// @endcode
208/// @}
209/** @} */
210/** @} */
211
212/** @addtogroup bsl
213 * @{
214 */
215/** @addtogroup bslalg
216 * @{
217 */
218/** @addtogroup bslalg_bidirectionallinklistutil
219 * @{
220 */
221
222#include <bslscm_version.h>
223
224
225
226namespace bslalg {
227
228class BidirectionalLink;
229
230 // ========================================
231 // struct bslalg::BidirectionalLinkListUtil
232 // ========================================
233
234/// This `struct` provides a namespace for utility functions that manipulate
235/// linked lists based on `bslalg::BidirectionalLink` nodes, including
236/// insertion, removal, and *splicing*.
238
239 // CLASS METHODS
240
241 /// Insert the specified `newNode` before the specified `target` node in
242 /// the linked list that contains `target`. If `target` is 0, then the
243 /// value of the attributes `nextLink` and `previousLink` of `newNode`
244 /// is set to 0. After successful execution of this function the values
245 /// of the `previousLink` and `nextLink` attributes of all the links in
246 /// the list appropriately reflect the operation. The behavior is
247 /// undefined unless `0 == target->previousLink()` is true or
248 /// `isWellFormed(target->previousLink(), target)` is true.
249 static
251 BidirectionalLink *target);
252
253 /// Insert the specified `newNode` after the specified `target` node in
254 /// the linked list that contains `target`. If the node following
255 /// `target` is 0, then set the `nextLink` attribute of `newNode` to 0.
256 /// After successful execution of this function the values of the
257 /// `previousLink` and `nextLink` attributes of all the links in the
258 /// list appropriately reflect the operation. The behavior is undefined
259 /// unless `0 != newNode` and `0 != target`. The behavior is also
260 /// undefined unless `0 == target->nextLink()` is true or
261 /// `isWellFormed(target, target->nextLink())` are true.
262 static
264 BidirectionalLink *target);
265
266 /// Return true if the bidirectional list starting from the specified
267 /// `head`, and ending with the specified `tail` is well formed. A
268 /// bidirectional list is well formed if `tail == head` (0 values are
269 /// allowed) or all of the following conditions are met (note that
270 /// `head` is renamed to `h` and `tail` to `t` for brevity):
271 ///
272 /// 1. `h` and `t` are valid addresses.
273 /// 2. `h->nextLink()->previousLink() == h` is true.
274 /// 3. `!h->previousLink() || h->previousLink()->nextLink() == h`
275 /// is true.
276 /// 4. `t->previousLink()->nextLink() == t` is true.
277 /// 5. `!t->nextLink() || t->nextLink()->previousLink() == t`
278 /// is true.
279 /// 6. For each `link` in the list different than `h` and `t` both
280 /// `link->nextLink()->previousLink() == link` and
281 /// `link->previousLink()->nextLink() == link` are true.
282 ///
283 /// The behavior is undefined unless `tail` can be reached from `head`
284 /// following the chain of `nextLink` attributes of all the nodes in the
285 /// open range `[head, tail)`.
286 static
288
289 /// Unlink and move (splice) the elements of a doubly-linked list
290 /// included in the closed range `[first, last]` out of their original
291 /// list and into another doubly-linked list before the specified
292 /// `target` node. If `target` is 0, then the elements are extracted
293 /// and form a new list such that `0 == first->previousLink()` and
294 /// `0 == last->nextLink()`. After successful execution of this
295 /// function the values of the `previousLink` and `nextLink` attributes
296 /// of all the links in the origin and destination lists appropriately
297 /// reflect the operation. The behavior is undefined unless both
298 /// `first` and `last` are non-zero members of the same linked list;
299 /// `first` precedes `last` in the list, or `first == last`; `target` is
300 /// not a node contained in the closed range `[first, last]`; and
301 /// `isWellFormed(first, last)` is true.
302 static
304 BidirectionalLink *last,
305 BidirectionalLink *target);
306
307 /// Unlink the specified `node` from the linked list of which it is a
308 /// member. After successful execution of this function the values of
309 /// the `previousLink` and `nextLink` attributes of all the links in the
310 /// origin and destination lists appropriately reflect the operation
311 /// Note that this method does *not* change the value for the `nextLink`
312 /// and `previousLink` attributes of `node`. The behavior is
313 /// undefined unless `!node->previousLink()`, `!node->nextLink()`, or
314 /// `isWellFormed(node->previousLink(), node->nextLink())` are true.
315 static
317};
318
319} // close package namespace
320
321
322
323#endif
324
325// ----------------------------------------------------------------------------
326// Copyright 2013 Bloomberg Finance L.P.
327//
328// Licensed under the Apache License, Version 2.0 (the "License");
329// you may not use this file except in compliance with the License.
330// You may obtain a copy of the License at
331//
332// http://www.apache.org/licenses/LICENSE-2.0
333//
334// Unless required by applicable law or agreed to in writing, software
335// distributed under the License is distributed on an "AS IS" BASIS,
336// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
337// See the License for the specific language governing permissions and
338// limitations under the License.
339// ----------------------------- END-OF-FILE ----------------------------------
340
341/** @} */
342/** @} */
343/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlc_flathashmap.h:1805
Definition bslalg_bidirectionallinklistutil.h:237
static void insertLinkBeforeTarget(BidirectionalLink *newNode, BidirectionalLink *target)
static void insertLinkAfterTarget(BidirectionalLink *newNode, BidirectionalLink *target)
static void unlink(BidirectionalLink *node)
static void spliceListBeforeTarget(BidirectionalLink *first, BidirectionalLink *last, BidirectionalLink *target)
static bool isWellFormed(BidirectionalLink *head, BidirectionalLink *tail)