1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
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  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SoBaseList SoBaseList.h Inventor/lists/SoBaseList.h
35   \brief The SoBaseList class is a container for pointers to SoBase derived objects.
36 
37   \ingroup general
38 
39   The additional capability of the SoBaseList class over its parent
40   class, SbPList, is to automatically handle referencing and
41   dereferencing of items as they are added or removed from the lists.
42 */
43 
44 #include <Inventor/lists/SoBaseList.h>
45 #include <Inventor/misc/SoBase.h>
46 #include <cassert>
47 
48 // Convenience macro for casting array element from void * to SoBase *.
49 #define GET_BASEPTR(idx) ((SoBase *)SbPList::get(idx))
50 
51 
52 /*!
53   Default constructor.
54 */
SoBaseList(void)55 SoBaseList::SoBaseList(void)
56   : SbPList(), referencing(TRUE)
57 {
58 }
59 
60 /*!
61   Constructor with a hint about the maximum number of pointers in the
62   list.
63 
64   \sa SbPList::SbPList(const int)
65 */
SoBaseList(const int size)66 SoBaseList::SoBaseList(const int size)
67   : SbPList(size), referencing(TRUE)
68 {
69 }
70 
71 /*!
72   Copy constructor.
73 
74   Shallow copy the items of \a l into this list, adding to the item
75   reference counts if the reference flag of \a l is \c TRUE.
76 
77   \sa SbPList::SbPList(const SbPList &)
78 */
SoBaseList(const SoBaseList & l)79 SoBaseList::SoBaseList(const SoBaseList & l)
80   : SbPList(l) // copies list items "raw"
81 {
82   this->referencing = l.referencing;
83   if (this->referencing) {
84     const int n = this->getLength();
85     for (int i = 0; i < n; i++) GET_BASEPTR(i)->ref();
86   }
87 }
88 
89 /*!
90   Destructor. Dereferences items before freeing resources.
91 */
~SoBaseList()92 SoBaseList::~SoBaseList()
93 {
94   this->truncate(0); // truncate() does unref-ing
95 }
96 
97 /*!
98   Append \a ptr to list, adding to the reference count of the object
99   (unless addReferences() has been set to \c FALSE).
100 
101   \sa SbPList::append()
102 */
103 void
append(SoBase * ptr)104 SoBaseList::append(SoBase * ptr)
105 {
106   if (this->referencing && ptr) ptr->ref();
107   SbPList::append((void *)ptr);
108 }
109 
110 /*!
111   Insert \a ptr in the list at position \a addbefore, adding to the
112   reference count of the object (unless addReferences() has been set
113   to \c FALSE).
114 
115   \sa SbPList::insert()
116 */
117 void
insert(SoBase * ptr,const int addbefore)118 SoBaseList::insert(SoBase * ptr, const int addbefore)
119 {
120   if (this->referencing && ptr) ptr->ref();
121   SbPList::insert((void *)ptr, addbefore);
122 }
123 
124 /*!
125   Removes item at \a index from the list, dereferencing the object
126   (unless addReferences() has been set to \c FALSE).
127 
128   \sa SbPList::remove()
129 */
130 void
remove(const int index)131 SoBaseList::remove(const int index)
132 {
133   assert(index >= 0 && index < this->getLength());
134   if (this->referencing && GET_BASEPTR(index) != NULL)
135     GET_BASEPTR(index)->unref();
136   SbPList::remove(index);
137 }
138 
139 /*!
140   Removes \a item from the list, dereferencing the object (unless
141   addReferences() has been set to \c FALSE).
142 
143   \sa SbPList::removeItem()
144 */
145 void
removeItem(SoBase * item)146 SoBaseList::removeItem(SoBase * item)
147 {
148   // We need to override the removeItem() function from our SbPList
149   // superclass, or invocations of it will not cause a decrease of the
150   // reference count.
151 
152   // Just forward call to remove(), which takes care of the
153   // dereferencing.
154   this->remove(this->find(item));
155 }
156 
157 /*!
158   Makes the list contain only the \a length first items, removing all
159   items from index \a length and onwards to the end of the
160   list. Dereferences the objects to be removed (unless addReferences()
161   has been set to \c FALSE).
162 
163   \sa SbPList::truncate()
164 */
165 void
truncate(const int length)166 SoBaseList::truncate(const int length)
167 {
168   if (this->referencing) {
169     const int n = this->getLength();
170     for (int i = length; i < n; i++)
171       if (GET_BASEPTR(i) != NULL) GET_BASEPTR(i)->unref();
172   }
173   SbPList::truncate(length);
174 }
175 
176 /*!
177   Shallow copy of the item pointers of \a l list into this one, first
178   removing all items in this list.
179 */
180 void
copy(const SoBaseList & l)181 SoBaseList::copy(const SoBaseList & l)
182 {
183   if (this == &l) return;
184 
185   this->truncate(0);
186 
187   this->referencing = l.referencing;
188   const int n = l.getLength();
189   for (int i = 0; i < n; i++) this->append(l[i]); // handles ref'ing
190 }
191 
192 /*!
193   Shallow copy of the SoBase pointers from \a l into this one,
194   returning a pointer to ourself.
195 
196   \sa copy()
197 */
198 SoBaseList &
operator =(const SoBaseList & l)199 SoBaseList::operator=(const SoBaseList & l)
200 {
201   this->copy(l);
202   return *this;
203 }
204 
205 /*!
206   Returns element at \a idx.
207 
208   Will automatically expand the size of the internal array if \a idx
209   is outside the current bounds of the list. The values of any
210   additional pointers are then set to \c NULL.
211 */
212 SoBase *
operator [](const int idx) const213 SoBaseList::operator[](const int idx) const
214 {
215   // Overridden from superclass to cast from the \c void pointer
216   // actually stored.
217 
218   return (SoBase *)SbPList::operator[](idx);
219 }
220 
221 /*!
222   Decide whether or not the SoBase items should be automatically
223   referenced and dereferenced as they are added and removed from the
224   list.
225 
226   Default setting is to do referencing.
227 */
228 void
addReferences(const SbBool flag)229 SoBaseList::addReferences(const SbBool flag)
230 {
231 #if 0 // OBSOLETED: don't do this, it looks like it could give the
232       // user some nasty surprises. 20000228 mortene.
233 
234   // this method should probably never be called when there are items in
235   // the list, but I think the code below should handle that case also.
236   // If refing changes from on to off, all items are unref'ed, since
237   // they were ref'ed when inserted. If state changes from off to on, all
238   // items are ref'ed, since they will be unref'ed when removed from list.
239 
240   if (flag == this->referencing) return; // no change
241 
242   const int n = this->getLength();
243   for (int i = 0; i < n; i++) {
244     SoBase * item = GET_BASEPTR(i);
245     if (item) {
246       if (flag) item->ref();
247       else item->unref();
248     }
249   }
250 
251 #else
252 
253   assert(this->getLength() == 0);
254 
255 #endif
256 
257   this->referencing = flag;
258 }
259 
260 /*!
261   Return whether the SoBase instances are automatically referenced
262   and dereferenced when they are added and removed from the list.
263 
264   \COIN_FUNCTION_EXTENSION
265 
266   \sa addReferences()
267   \since Coin 2.0
268 */
269 SbBool
isReferencing(void) const270 SoBaseList::isReferencing(void) const
271 {
272   return this->referencing;
273 }
274 
275 /*!
276   Index operator to set element at \a i. Does \e not expand array
277   bounds if \a i is outside the list.
278 */
279 void
set(const int i,SoBase * const ptr)280 SoBaseList::set(const int i, SoBase * const ptr)
281 {
282   // Overridden from parent class to provide referencing on the SoBase
283   // object.
284 
285   if (this->referencing) {
286     // Note: it's important to ref() before we unref(), in case the
287     // value of ptr is equal to the old value (otherwise we could
288     // unref() it to zero, which causes premature destruction).
289     if (ptr) ptr->ref();
290     if (GET_BASEPTR(i)) GET_BASEPTR(i)->unref();
291   }
292   SbPList::set(i, (void *)ptr);
293 }
294 
295 
296 #undef GET_BASEPTR
297