1 /*************************************************************************
2 This software is part of a public domain IronDoc source code distribution,
3 and is provided on an "AS IS" basis, with all risks borne by the consumers
4 or users of the IronDoc software. There are no warranties, guarantees, or
5 promises about quality of any kind; and no remedies for failure exist.
7 Permission is hereby granted to use this IronDoc software for any purpose
8 at all, without need for written agreements, without royalty or license
9 fees, and without fees or obligations of any other kind. Anyone can use,
10 copy, change and distribute this software for any purpose, and nothing is
11 required, implicitly or otherwise, in exchange for this usage.
13 You cannot apply your own copyright to this software, but otherwise you
14 are encouraged to enjoy the use of this software in any way you see fit.
15 However, it would be rude to remove names of developers from the code.
16 (IronDoc is also known by the short name "Fe" and a longer name "Ferrum",
17 which are used interchangeably with the name IronDoc in the sources.)
18 *************************************************************************/
21 * Contains: Ferrum deque (double ended queue (linked list))
23 * Copied directly from public domain IronDoc, with minor naming tweaks:
24 * Designed and written by David McCusker, but all this code is public domain.
25 * There are no warranties, no guarantees, no promises, and no remedies.
35 /*=============================================================================
36 * morkNext: linked list node for very simple, singly-linked list
39 class morkNext
/*d*/ {
44 morkNext(int inZero
) : mNext_Link( 0 ) { }
46 morkNext(morkNext
* ioLink
) : mNext_Link( ioLink
) { }
48 morkNext(); // mNext_Link( 0 ), { }
51 morkNext
* GetNextLink() const { return mNext_Link
; }
53 public: // link memory management methods
54 static void* MakeNewNext(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
);
55 void ZapOldNext(morkEnv
* ev
, nsIMdbHeap
* ioHeap
);
57 public: // link memory management operators
58 void* operator new(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
) CPP_THROW_NEW
59 { return morkNext::MakeNewNext(inSize
, ioHeap
, ev
); }
61 void operator delete(void* ioAddress
) // DO NOT CALL THIS, hope to crash:
62 { ((morkNext
*) 0)->ZapOldNext((morkEnv
*) 0, (nsIMdbHeap
*) 0); } // boom
65 /*=============================================================================
66 * morkList: simple, singly-linked list
69 /*| morkList: a list of singly-linked members (instances of morkNext), where
70 **| the number of list members might be so numerous that we must about cost
71 **| for two pointer link slots per member (as happens with morkLink).
73 **|| morkList is intended to support lists of changes in morkTable, where we
74 **| are worried about the space cost of representing such changes. (Later we
75 **| can use an array instead, when we get even more worried, to avoid cost
76 **| of link slots at all, per member).
78 **|| Do NOT create cycles in links using this list class, since we do not
79 **| deal with them very nicely.
81 class morkList
/*d*/ {
83 morkNext
* mList_Head
; // first link in the list
84 morkNext
* mList_Tail
; // last link in the list
87 morkNext
* GetListHead() const { return mList_Head
; }
88 morkNext
* GetListTail() const { return mList_Tail
; }
90 mork_bool
IsListEmpty() const { return ( mList_Head
== 0 ); }
91 mork_bool
HasListMembers() const { return ( mList_Head
!= 0 ); }
94 morkList(); // : mList_Head( 0 ), mList_Tail( 0 ) { }
96 void CutAndZapAllListMembers(morkEnv
* ev
, nsIMdbHeap
* ioHeap
);
97 // make empty list, zapping every member by calling ZapOldNext()
99 void CutAllListMembers();
100 // just make list empty, dropping members without zapping
103 morkNext
* PopHead(); // cut head of list
105 // Note we don't support PopTail(), so use morkDeque if you need that.
107 void PushHead(morkNext
* ioLink
); // add to head of list
108 void PushTail(morkNext
* ioLink
); // add to tail of list
111 /*=============================================================================
112 * morkLink: linked list node embedded in objs to allow insertion in morkDeques
115 class morkLink
/*d*/ {
117 morkLink
* mLink_Next
;
118 morkLink
* mLink_Prev
;
121 morkLink(int inZero
) : mLink_Next( 0 ), mLink_Prev( 0 ) { }
123 morkLink(); // mLink_Next( 0 ), mLink_Prev( 0 ) { }
126 morkLink
* Next() const { return mLink_Next
; }
127 morkLink
* Prev() const { return mLink_Prev
; }
129 void SelfRefer() { mLink_Next
= mLink_Prev
= this; }
130 void Clear() { mLink_Next
= mLink_Prev
= 0; }
132 void AddBefore(morkLink
* old
)
134 ((old
)->mLink_Prev
->mLink_Next
= (this))->mLink_Prev
= (old
)->mLink_Prev
;
135 ((this)->mLink_Next
= (old
))->mLink_Prev
= this;
138 void AddAfter(morkLink
* old
)
140 ((old
)->mLink_Next
->mLink_Prev
= (this))->mLink_Next
= (old
)->mLink_Next
;
141 ((this)->mLink_Prev
= (old
))->mLink_Next
= this;
146 (mLink_Prev
->mLink_Next
= mLink_Next
)->mLink_Prev
= mLink_Prev
;
149 public: // link memory management methods
150 static void* MakeNewLink(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
);
151 void ZapOldLink(morkEnv
* ev
, nsIMdbHeap
* ioHeap
);
153 public: // link memory management operators
154 void* operator new(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
) CPP_THROW_NEW
155 { return morkLink::MakeNewLink(inSize
, ioHeap
, ev
); }
159 /*=============================================================================
160 * morkDeque: doubly linked list modeled after VAX queue instructions
163 class morkDeque
/*d*/ {
165 morkLink mDeque_Head
;
167 public: // construction
168 morkDeque(); // { mDeque_Head.SelfRefer(); }
171 morkLink
* RemoveFirst();
173 morkLink
* RemoveLast();
175 morkLink
* At(mork_pos index
) const ; /* one-based, not zero-based */
177 mork_pos
IndexOf(const morkLink
* inMember
) const;
178 /* one-based index ; zero means member is not in deque */
180 mork_num
Length() const;
182 /* the following method is more efficient for long lists: */
183 int LengthCompare(mork_num inCount
) const;
184 /* -1: length < count, 0: length == count, 1: length > count */
188 mork_bool
IsEmpty()const
189 { return (mDeque_Head
.mLink_Next
== (morkLink
*) &mDeque_Head
); }
191 morkLink
* After(const morkLink
* old
) const
192 { return (((old
)->mLink_Next
!= &mDeque_Head
)?
193 (old
)->mLink_Next
: (morkLink
*) 0); }
195 morkLink
* Before(const morkLink
* old
) const
196 { return (((old
)->mLink_Prev
!= &mDeque_Head
)?
197 (old
)->mLink_Prev
: (morkLink
*) 0); }
199 morkLink
* First() const
200 { return ((mDeque_Head
.mLink_Next
!= &mDeque_Head
)?
201 mDeque_Head
.mLink_Next
: (morkLink
*) 0); }
203 morkLink
* Last() const
204 { return ((mDeque_Head
.mLink_Prev
!= &mDeque_Head
)?
205 mDeque_Head
.mLink_Prev
: (morkLink
*) 0); }
208 From IronDoc documentation for AddFirst:
209 +--------+ +--------+ +--------+ +--------+ +--------+
210 | h.next |-->| b.next | | h.next |-->| a.next |-->| b.next |
211 +--------+ +--------+ ==> +--------+ +--------+ +--------+
212 | h.prev |<--| b.prev | | h.prev |<--| a.prev |<--| b.prev |
213 +--------+ +--------+ +--------+ +--------+ +--------+
216 void AddFirst(morkLink
* in
) /*i*/
218 ( (mDeque_Head
.mLink_Next
->mLink_Prev
=
219 (in
))->mLink_Next
= mDeque_Head
.mLink_Next
,
220 ((in
)->mLink_Prev
= &mDeque_Head
)->mLink_Next
= (in
) );
223 From IronDoc documentation for AddLast:
224 +--------+ +--------+ +--------+ +--------+ +--------+
225 | y.next |-->| h.next | | y.next |-->| z.next |-->| h.next |
226 +--------+ +--------+ ==> +--------+ +--------+ +--------+
227 | y.prev |<--| h.prev | | y.prev |<--| z.prev |<--| h.prev |
228 +--------+ +--------+ +--------+ +--------+ +--------+
231 void AddLast(morkLink
* in
)
233 ( (mDeque_Head
.mLink_Prev
->mLink_Next
=
234 (in
))->mLink_Prev
= mDeque_Head
.mLink_Prev
,
235 ((in
)->mLink_Next
= &mDeque_Head
)->mLink_Prev
= (in
) );
239 #endif /* _MORKDEQUE_ */