1 /*****************************************************************
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ****************************************************************/
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
38 #include "NptResults.h"
40 #include "NptConstants.h"
41 #include "NptCommon.h"
43 /*----------------------------------------------------------------------
45 +---------------------------------------------------------------------*/
46 const int NPT_ERROR_LIST_EMPTY
= NPT_ERROR_BASE_LIST
- 0;
47 const int NPT_ERROR_LIST_OPERATION_ABORTED
= NPT_ERROR_BASE_LIST
- 1;
48 const int NPT_ERROR_LIST_OPERATION_CONTINUE
= NPT_ERROR_BASE_LIST
- 2;
50 /*----------------------------------------------------------------------
52 +---------------------------------------------------------------------*/
65 Iterator() : m_Item(NULL
) {}
66 explicit Iterator(Item
* item
) : m_Item(item
) {}
67 Iterator(const Iterator
& copy
) : m_Item(copy
.m_Item
) {}
68 T
& operator*() const { return m_Item
->m_Data
; }
69 T
* operator->() const { return &m_Item
->m_Data
;}
70 Iterator
& operator++() { // prefix
71 m_Item
= m_Item
->m_Next
;
74 Iterator
operator++(int) { // postfix
75 Iterator saved_this
= *this;
76 m_Item
= m_Item
->m_Next
;
79 Iterator
& operator--() { // prefix
80 m_Item
= m_Item
->m_Prev
;
83 Iterator
operator--(int) { // postfix
84 Iterator saved_this
= *this;
85 m_Item
= m_Item
->m_Prev
;
88 operator bool() const {
89 return m_Item
!= NULL
;
91 bool operator==(const Iterator
& other
) const {
92 return m_Item
== other
.m_Item
;
94 bool operator!=(const Iterator
& other
) const {
95 return m_Item
!= other
.m_Item
;
97 void operator=(const Iterator
& other
) {
98 m_Item
= other
.m_Item
;
100 void operator=(Item
* item
) {
108 friend class NPT_List
<T
>;
113 NPT_List(const NPT_List
<T
>& list
);
115 NPT_Result
Add(const T
& data
);
116 NPT_Result
Insert(const Iterator where
, const T
& data
);
117 NPT_Result
Remove(const T
& data
, bool all
=false);
118 NPT_Result
Erase(const Iterator position
);
119 NPT_Result
PopHead(T
& data
);
120 bool Contains(const T
& data
) const;
122 NPT_Result
Get(NPT_Ordinal index
, T
& data
) const;
123 NPT_Result
Get(NPT_Ordinal index
, T
*& data
) const;
124 NPT_Cardinal
GetItemCount() const { return m_ItemCount
; }
125 Iterator
GetFirstItem() const { return Iterator(m_Head
); }
126 Iterator
GetLastItem() const { return Iterator(m_Tail
); }
127 Iterator
GetItem(NPT_Ordinal index
) const;
130 NPT_Result
Add(NPT_List
<T
>& list
);
131 NPT_Result
Remove(const NPT_List
<T
>& list
, bool all
=false);
132 NPT_Result
Cut(NPT_Cardinal keep
, NPT_List
<T
>& cut
);
135 NPT_Result
Add(Item
& item
);
136 NPT_Result
Detach(Item
& item
);
137 NPT_Result
Insert(const Iterator where
, Item
& item
);
140 // keep these template members defined here because MSV6 does not let
141 // us define them later
142 template <typename X
>
143 NPT_Result
Apply(const X
& function
) const
147 function(item
->m_Data
);
154 template <typename X
, typename P
>
155 NPT_Result
ApplyUntil(const X
& function
, const P
& predicate
, bool* match
= NULL
) const
159 NPT_Result return_value
;
160 if (predicate(function(item
->m_Data
), return_value
)) {
161 if (match
) *match
= true;
167 if (match
) *match
= false;
171 template <typename P
>
172 Iterator
Find(const P
& predicate
, NPT_Ordinal n
=0) const
176 if (predicate(item
->m_Data
)) {
178 return Iterator(item
);
185 return Iterator(NULL
);
188 // Merge sort algorithm
189 // http://en.wikipedia.org/wiki/Mergesort
190 template <typename X
>
191 NPT_Result
Sort(const X
& function
)
193 if (GetItemCount() <= 1) return NPT_SUCCESS
;
196 NPT_CHECK(Cut(GetItemCount() >> 1, right
));
198 // sort the left side
201 // sort the right side
202 right
.Sort(function
);
204 // merge the two back inline
205 if (function(m_Tail
->m_Data
, right
.m_Head
->m_Data
) > 0) {
206 Merge(right
, function
);
209 right
.m_Head
->m_Prev
= m_Tail
;
210 m_Tail
->m_Next
= right
.m_Head
;
211 m_Tail
= right
.m_Tail
;
212 m_ItemCount
+= right
.m_ItemCount
;
214 right
.m_ItemCount
= 0;
215 right
.m_Head
= right
.m_Tail
= NULL
;
221 template <typename X
>
222 NPT_Result
Merge(NPT_List
<T
>& other
, const X
& function
)
224 Iterator left
= GetFirstItem();
226 while (left
&& other
.m_Head
) {
227 if (function(*left
, other
.m_Head
->m_Data
) <= 0) {
230 // remove head and insert it
231 Item
* head
= other
.m_Head
;
237 // add what's left of other if any
239 other
.m_Head
->m_Prev
= m_Tail
;
240 if (m_Tail
) m_Tail
->m_Next
= other
.m_Head
;
241 m_Tail
= other
.m_Tail
;
242 if (!m_Head
) m_Head
= other
.m_Head
;
243 other
.m_Head
= other
.m_Tail
= NULL
;
245 m_ItemCount
+= other
.m_ItemCount
;
246 other
.m_ItemCount
= 0;
251 void operator=(const NPT_List
<T
>& other
);
252 bool operator==(const NPT_List
<T
>& other
) const;
253 bool operator!=(const NPT_List
<T
>& other
) const;
261 Item(const T
& data
) : m_Next(0), m_Prev(0), m_Data(data
) {}
269 //friend class NPT_List<T>;
270 //friend class NPT_List<T>::Iterator;
274 NPT_Cardinal m_ItemCount
;
279 /*----------------------------------------------------------------------
280 | NPT_List<T>::NPT_List
281 +---------------------------------------------------------------------*/
282 template <typename T
>
284 NPT_List
<T
>::NPT_List() : m_ItemCount(0), m_Head(0), m_Tail(0)
288 /*----------------------------------------------------------------------
289 | NPT_List<T>::NPT_List
290 +---------------------------------------------------------------------*/
291 template <typename T
>
293 NPT_List
<T
>::NPT_List(const NPT_List
<T
>& list
) : m_ItemCount(0), m_Head(0), m_Tail(0)
298 /*----------------------------------------------------------------------
299 | NPT_List<T>::~NPT_List<T>
300 +---------------------------------------------------------------------*/
301 template <typename T
>
303 NPT_List
<T
>::~NPT_List()
308 /*----------------------------------------------------------------------
309 | NPT_List<T>::operator=
310 +---------------------------------------------------------------------*/
311 template <typename T
>
313 NPT_List
<T
>::operator=(const NPT_List
<T
>& list
)
319 Item
* item
= list
.m_Head
;
326 /*----------------------------------------------------------------------
327 | NPT_List<T>::operator==
328 +---------------------------------------------------------------------*/
329 template <typename T
>
331 NPT_List
<T
>::operator==(const NPT_List
<T
>& other
) const
334 if (m_ItemCount
!= other
.m_ItemCount
) return false;
336 // compare all elements one by one
337 Item
* our_item
= m_Head
;
338 Item
* their_item
= other
.m_Head
;
339 while (our_item
&& their_item
) {
340 if (our_item
->m_Data
!= their_item
->m_Data
) return false;
341 our_item
= our_item
->m_Next
;
342 their_item
= their_item
->m_Next
;
345 return our_item
== NULL
&& their_item
== NULL
;
348 /*----------------------------------------------------------------------
349 | NPT_List<T>::operator!=
350 +---------------------------------------------------------------------*/
351 template <typename T
>
354 NPT_List
<T
>::operator!=(const NPT_List
<T
>& other
) const
356 return !(*this == other
);
359 /*----------------------------------------------------------------------
361 +---------------------------------------------------------------------*/
362 template <typename T
>
369 Item
* next
= item
->m_Next
;
381 /*----------------------------------------------------------------------
383 +---------------------------------------------------------------------*/
384 template <typename T
>
386 NPT_List
<T
>::Add(Item
& item
)
388 // add element at the tail
390 item
.m_Prev
= m_Tail
;
392 m_Tail
->m_Next
= &item
;
401 // one more item in the list now
407 /*----------------------------------------------------------------------
409 +---------------------------------------------------------------------*/
410 template <typename T
>
412 NPT_List
<T
>::Add(NPT_List
<T
>& list
)
415 Item
* item
= list
.m_Head
;
424 /*----------------------------------------------------------------------
426 +---------------------------------------------------------------------*/
427 template <typename T
>
430 NPT_List
<T
>::Add(const T
& data
)
432 return Add(*new Item(data
));
435 /*----------------------------------------------------------------------
436 | NPT_List<T>::GetItem
437 +---------------------------------------------------------------------*/
438 template <typename T
>
439 typename NPT_List
<T
>::Iterator
440 NPT_List
<T
>::GetItem(NPT_Ordinal n
) const
443 if (n
>= m_ItemCount
) return result
;
446 for (unsigned int i
=0; i
<n
; i
++) {
453 /*----------------------------------------------------------------------
454 | NPT_List<T>::Insert
455 +---------------------------------------------------------------------*/
456 template <typename T
>
459 NPT_List
<T
>::Insert(Iterator where
, const T
&data
)
461 return Insert(where
, *new Item(data
));
464 /*----------------------------------------------------------------------
465 | NPT_List<T>::Insert
466 +---------------------------------------------------------------------*/
467 template <typename T
>
469 NPT_List
<T
>::Insert(Iterator where
, Item
& item
)
471 // insert the item in the list
472 Item
* position
= where
.m_Item
;
474 // insert at position
475 item
.m_Next
= position
;
476 item
.m_Prev
= position
->m_Prev
;
477 position
->m_Prev
= &item
;
479 item
.m_Prev
->m_Next
= &item
;
481 // this is the new head
485 // one more item in the list now
495 /*----------------------------------------------------------------------
497 +---------------------------------------------------------------------*/
498 template <typename T
>
500 NPT_List
<T
>::Erase(Iterator position
)
502 if (!position
) return NPT_ERROR_NO_SUCH_ITEM
;
503 Detach(*position
.m_Item
);
504 delete position
.m_Item
;
509 /*----------------------------------------------------------------------
510 | NPT_List<T>::Remove
511 +---------------------------------------------------------------------*/
512 template <typename T
>
514 NPT_List
<T
>::Remove(const T
& data
, bool all
)
517 NPT_Cardinal matches
= 0;
520 Item
* next
= item
->m_Next
;
521 if (item
->m_Data
== data
) {
531 if (!all
) return NPT_SUCCESS
;
536 return matches
?NPT_SUCCESS
:NPT_ERROR_NO_SUCH_ITEM
;
539 /*----------------------------------------------------------------------
540 | NPT_List<T>::Remove
541 +---------------------------------------------------------------------*/
542 template <typename T
>
544 NPT_List
<T
>::Remove(const NPT_List
<T
>& list
, bool all
)
546 Item
* item
= list
.m_Head
;
548 Remove(item
->m_Data
, all
);
555 /*----------------------------------------------------------------------
556 | NPT_List<T>::Detach
557 +---------------------------------------------------------------------*/
558 template <typename T
>
560 NPT_List
<T
>::Detach(Item
& item
)
564 // item is not the head
566 // item is not the tail
567 item
.m_Next
->m_Prev
= item
.m_Prev
;
568 item
.m_Prev
->m_Next
= item
.m_Next
;
571 m_Tail
= item
.m_Prev
;
572 m_Tail
->m_Next
= NULL
;
576 m_Head
= item
.m_Next
;
578 // item is not the tail
579 m_Head
->m_Prev
= NULL
;
581 // item is also the tail
586 // one less item in the list now
592 /*----------------------------------------------------------------------
594 +---------------------------------------------------------------------*/
595 template <typename T
>
597 NPT_List
<T
>::Get(NPT_Ordinal index
, T
& data
) const
600 NPT_CHECK(Get(index
, data_pointer
));
601 data
= *data_pointer
;
605 /*----------------------------------------------------------------------
607 +---------------------------------------------------------------------*/
608 template <typename T
>
610 NPT_List
<T
>::Get(NPT_Ordinal index
, T
*& data
) const
614 if (index
< m_ItemCount
) {
615 while (index
--) item
= item
->m_Next
;
616 data
= &item
->m_Data
;
620 return NPT_ERROR_NO_SUCH_ITEM
;
624 /*----------------------------------------------------------------------
625 | NPT_List<T>::PopHead
626 +---------------------------------------------------------------------*/
627 template <typename T
>
629 NPT_List
<T
>::PopHead(T
& data
)
631 // check that we have an element
632 if (m_Head
== NULL
) return NPT_ERROR_LIST_EMPTY
;
634 // copy the head item's data
635 data
= m_Head
->m_Data
;
637 // discard the head item
639 m_Head
= m_Head
->m_Next
;
641 m_Head
->m_Prev
= NULL
;
653 /*----------------------------------------------------------------------
654 | NPT_List<T>::Contains
655 +---------------------------------------------------------------------*/
656 template <typename T
>
658 NPT_List
<T
>::Contains(const T
& data
) const
662 if (item
->m_Data
== data
) return true;
669 /*----------------------------------------------------------------------
671 +---------------------------------------------------------------------*/
672 template <typename T
>
674 NPT_List
<T
>::Cut(NPT_Cardinal keep
, NPT_List
<T
>& cut
)
679 if (keep
>= GetItemCount()) return NPT_SUCCESS
;
681 // update new counts first
682 cut
.m_ItemCount
= m_ItemCount
-keep
;
685 // look for the cut-point item
687 while (keep
--) { item
= item
->m_Next
;}
689 // the cut list goes from the cut-point item to the tail
693 // update the portion of the list we keep
694 if (item
== m_Head
) m_Head
= NULL
;
695 m_Tail
= item
->m_Prev
;
697 // update the cut list
698 if (item
->m_Prev
) item
->m_Prev
->m_Next
= NULL
;
704 #endif // _NPT_LIST_H_