1 : /* _________________________________________________________________________
2 : *
3 : * UTILIB: A utility library for developing portable C++ codes.
4 : * Copyright (c) 2001, Sandia National Laboratories.
5 : * This software is distributed under the GNU Lesser General Public License.
6 : * For more information, see the README file in the top UTILIB directory.
7 : * _________________________________________________________________________
8 : */
9 :
10 : /**
11 : * \file ArrayBase.h
12 : *
13 : * Defines the utilib::ArrayBase class
14 : */
15 :
16 : #ifndef utilib_ArrayBase_h
17 : #define utilib_ArrayBase_h
18 :
19 : #include <utilib/std_headers.h>
20 : #include <utilib/_generic.h>
21 : #include <utilib/exception_mngr.h>
22 :
23 : #include <utilib/Serialize.h>
24 :
25 : namespace utilib {
26 :
27 : /**
28 : * \def ArraySanityChecking
29 : *
30 : * If the macro ArraySanityChecking=1 then some routine sanity checks will
31 : * be performed when accessing vectors. Sanity checking generally degrades
32 : * performance. The default is is to perform sanity checking.
33 : *
34 : * Note: Because inlines are typically put "in place" when the optimization flag
35 : * -O is used, you can define some files with ArraySanityChecking=0 to
36 : * acheive better performance, while using the default debugging mode in the
37 : * rest of the code.
38 : */
39 : #if !defined(ArraySanityChecking)
40 : #define ArraySanityChecking 1
41 : #endif
42 :
43 : template <class A, class P>
44 : class ArrayBase;
45 :
46 :
47 : /**
48 : * This class implements sharable array objects. This class implements
49 : * features common to both regular arrays, such as BasicArray<T>,
50 : * SimpleArray<T>, NumArray<T>, {Int,Real,Double}Vector, and CharString,
51 : * and also bit-oriented arrays implemented via the BitArrayBase class.
52 : *
53 : * It is essentially a replacement for the old ClassRef class, but
54 : * (for the time being, at least), only works for array-like objects
55 : * that have a "length".
56 : *
57 : * The template argument "A" refers to what kind of memory objects
58 : * are actually allocated. The template argument "P" refers to what
59 : * kinds of pointers are stored to other objects sharing the same memory.
60 : *
61 : * This class differs from ClassRef in that sharing is implemented
62 : * via an embedded linked list instead of a separate
63 : * ArrayRef/ClassRef object. That means there are two "extra" pointers
64 : * in the array object, but sharing is fairly simple, without any
65 : * overhead being imposed on the indexing [ ] operator. The tradeoff
66 : * is that resizing a shared array carries O(s) overhead, where s
67 : * is the number of sharers. Deletion is O(1), however.
68 : *
69 : */
70 : template <class A, class P>
71 : class ArrayBase
72 2491781 : {
73 : public:
74 :
75 : /// Destructor
76 2484655 : virtual ~ArrayBase()
77 2484655 : { free(); }
78 :
79 : /// Returns true if this array shares data with another array.
80 3 : bool shared_mem() const
81 3 : { return true_pointer(prev_share) || next_share; }
82 :
83 : /// Resizes the array to the given, nonnegative, value.
84 : /// If the second argument is non-zero (the default), the old contents
85 : /// are copied, and if the new array is longer, the new elements
86 : /// are set with the \b initialize method.
87 : virtual void resize(const size_type newl,int set_new_contents=1);
88 :
89 : /// Returns true if size == 0 (for STL compatibility)
90 0 : bool empty() const
91 0 : { return Len == 0; }
92 :
93 : /// Returns the length of the array.
94 14153277 : size_type size() const
95 14153277 : { return Len; }
96 :
97 : /// This method controls the mapping of the size of the array
98 : /// to the actual number of type "A" elements allocated. The
99 : /// default implementation is the identity mapping, which should
100 : /// work for everything except BitArrays and CharStrings.
101 2644683 : virtual size_type alloc_size(size_type l) const
102 2644683 : { return l; }
103 :
104 : /// Same, but takes the size of the array as an effective default argument
105 0 : size_type allocation() const
106 0 : { return alloc_size(Len); }
107 :
108 : /// Returns the number of bytes used by the array
109 0 : size_type bytes_used() const
110 0 : { return allocation()*sizeof(A); }
111 :
112 : /// Returns the internal pointer to the array.
113 2406866 : A* data() const
114 2406866 : { return Data; }
115 :
116 : #if 0
117 : #ifndef SWIG
118 :
119 : /// A coercion operator returning a pointer to the internal array
120 : operator A* () const
121 : { return Data; }
122 :
123 : #endif
124 : #endif
125 :
126 : /// Returns the number of references to the internal array.
127 : /// This method has to scan the entire share group and is
128 : /// now deprecated.
129 : int nrefs() const;
130 :
131 : /// Disconnect from any prior data and copy the data from object \b array
132 : ArrayBase<A,P>& operator=(const ArrayBase<A,P>& array);
133 :
134 : /// Set to share storage with \b array
135 : ArrayBase<A,P>& operator&=(ArrayBase<A,P>& array);
136 :
137 : /// Method to explicitly set the Data pointer and length.
138 : /// Applies to all members of the share group.
139 : void set_data(const size_type len,
140 : A* data,
141 : const EnumDataOwned o=DataNotOwned);
142 :
143 : /// Print debugging information to a stream
144 : void debug_print(std::ostream& str,int max_elements=0);
145 :
146 : protected:
147 :
148 : /// The pointer to this array's data.
149 : A* Data;
150 :
151 : /// Pointer to the previous element of this share group.
152 : /// If the first in a group, and the data is not owned, contains
153 : /// the special pointer value special_not_owned_pointer().
154 : P* prev_share;
155 :
156 : /// Pointer to the next element of this share group.
157 : P* next_share;
158 :
159 : /// The length of the array in \a Data. This is set up so that
160 : /// it is always equal to the user's perceived length of the array.
161 : /// To get the actual number of type "A" elements allocated in \b Data,
162 : /// apply the \b alloc_size method below.
163 : size_type Len;
164 :
165 : /// This method copies from one data block to another. The
166 : /// default should suffice for regular arrays, but for BitArrays
167 : /// and CharStrings it will need some tweaking.
168 : virtual void copy_data(A* target,
169 : size_type target_size,
170 : A* source,
171 : size_type source_size);
172 :
173 : /// This method should be used by constructors of derived classes.
174 : virtual void construct(const size_type mylen,
175 : A* d=0,
176 : const EnumDataOwned o=DataNotOwned);
177 :
178 : /// Supply initial values to part of an array. Default is
179 : /// a no-op, but for NumArrays this is overridden to set 0's.
180 : virtual void initialize(A* /*data*/,
181 : const size_type /*start*/,
182 136508 : const size_type /*stop*/)
183 136508 : {}
184 :
185 : /// Unlink from storage. Delete the associated memory if
186 : /// nobody else is linked to it.
187 : void free();
188 :
189 : /// Special bogus pointer to use to terminate the beginning of
190 : /// the list when the memory block is not owned by the array.
191 : /// We assume that just as no data can live at address 0, it
192 : /// can't live at address 1 either.
193 61696 : static P* special_not_owned_pointer()
194 61696 : { return (P*) 1; }
195 :
196 : /// Internal function for testing whether a pointer is valid.
197 : /// Checks for both NULL and the special_not_owned_pointer().
198 3738284 : static int true_pointer(P* p)
199 3738284 : { return p && (p != special_not_owned_pointer()); }
200 :
201 : /// Generic method for dumping contents to a stream (debugging only)
202 : /// Default is nothing.
203 0 : virtual void dump_data(std::ostream& /*str*/, unsigned int /*max_elements*/=0)
204 0 : {}
205 :
206 : /// The general serializer for all ArrayBase derivatives.
207 : static int serializer( SerialObject::elementList_t& serial,
208 : Any& data, bool serialize );
209 :
210 : };
211 :
212 :
213 : ///
214 : /// METHOD DEFINITIONS
215 : ///
216 :
217 : template <class A, class P>
218 : void ArrayBase<A,P>::construct(const size_type mylen,
219 : A* d,
220 3020956 : const EnumDataOwned o)
221 : {
222 3020956 : Len = mylen;
223 :
224 3020956 : if (d == NULL)
225 : {
226 2401407 : if (mylen > 0)
227 : {
228 128407 : size_type newlen = alloc_size(mylen);
229 128407 : Data = new A[newlen];
230 128407 : if (Data == 0)
231 0 : EXCEPTION_MNGR(runtime_error, "ArrayBase::construct - new A[" << alloc_size(mylen) << "] failed.");
232 128407 : initialize(Data,0,Len);
233 : }
234 : else
235 2273000 : Data = NULL;
236 : }
237 : else // if d was supplied...
238 : {
239 619549 : if (o == DataOwned) {
240 607599 : if (mylen > 0)
241 : {
242 607578 : size_type newlen = alloc_size(mylen);
243 607578 : Data = new A[newlen];
244 607578 : if (Data == 0)
245 0 : EXCEPTION_MNGR(runtime_error, "ArrayBase::construct - new A["
246 : << alloc_size(mylen) << "] failed.");
247 607578 : copy_data(Data,Len,d,Len);
248 : }
249 : }
250 : else
251 11950 : Data = d;
252 : }
253 :
254 : // Initialize the pointers to the rest of the share group, which is now
255 : // empty. Note that if the data is not owned, we use a special bogus value
256 : // instead of NULL for the first pointer.
257 :
258 3032906 : if ((o == DataNotOwned) && d)
259 11950 : prev_share = special_not_owned_pointer();
260 : else
261 3009006 : prev_share = NULL;
262 :
263 3020956 : next_share = NULL;
264 :
265 : }
266 :
267 :
268 : template <class A, class P>
269 2908938 : void ArrayBase<A,P>::free()
270 : {
271 : // Unlink from previous member of share group, if any
272 :
273 2908938 : if (true_pointer(prev_share))
274 34868 : prev_share->next_share = next_share;
275 :
276 : // Unlink from next member of share group, if any
277 :
278 2908938 : if (next_share)
279 2815 : next_share->prev_share = prev_share;
280 :
281 : // If there were no other members and the data is owned, free memory.
282 :
283 2908938 : if ((Data != NULL) && (prev_share == NULL) && (next_share == NULL))
284 1189115 : delete [] Data;
285 :
286 : }
287 :
288 :
289 : template <class A, class P>
290 : void ArrayBase<A,P>::copy_data(A* target,
291 : size_type target_size,
292 : A* source,
293 1036843 : size_type source_size)
294 : {
295 1036843 : size_type target_alloc = alloc_size(target_size);
296 1036843 : size_type source_alloc = alloc_size(source_size);
297 2687856 : for(size_type i=0; i < target_alloc && i < source_alloc; i++)
298 2687856 : *(target++) = *(source++);
299 : }
300 :
301 :
302 :
303 : template <class A, class P>
304 354389 : ArrayBase<A,P>& ArrayBase<A,P>::operator=(const ArrayBase<A,P>& array)
305 : {
306 354389 : if (this != &array)
307 : {
308 354389 : free();
309 354389 : construct(array.size(),array.data(),DataOwned);
310 : }
311 354389 : return *this;
312 : }
313 :
314 :
315 :
316 : template <class A, class P>
317 37681 : ArrayBase<A,P>& ArrayBase<A,P>::operator&=(ArrayBase<A,P>& array)
318 : {
319 37681 : if (this == &array)
320 1 : return *this;
321 :
322 37680 : if ((array.Data != Data) || (Data == NULL))
323 : {
324 37680 : free();
325 :
326 37680 : Data = array.Data;
327 37680 : Len = array.Len;
328 :
329 37680 : prev_share = array.prev_share;
330 37680 : if (true_pointer(array.prev_share))
331 4 : array.prev_share->next_share = (P*) this;
332 37680 : array.prev_share = (P*) this;
333 37680 : next_share = (P*) &array;
334 : }
335 37680 : return *this;
336 : }
337 :
338 :
339 :
340 : template <class A, class P>
341 1029658 : void ArrayBase<A,P>::resize(const size_type newl,int set_new_contents)
342 : {
343 1029658 : if (newl == Len)
344 240973 : return;
345 :
346 788685 : A* d = 0;
347 788685 : size_type new_alloc = alloc_size(newl);
348 :
349 788685 : if (new_alloc == alloc_size(Len))
350 68557 : d = Data;
351 720128 : else if (newl > 0)
352 : {
353 672763 : d = new A[new_alloc];
354 672763 : if (d == 0)
355 0 : EXCEPTION_MNGR(runtime_error, "ArrayBase::resize - new T ["
356 : << new_alloc << "] failed.");
357 672763 : if (set_new_contents)
358 672753 : copy_data(d,newl,Data,Len);
359 : }
360 :
361 788685 : if (set_new_contents && (newl > Len))
362 669550 : initialize(d,Len,newl);
363 :
364 788685 : set_data(newl,d,DataOwned);
365 : }
366 :
367 :
368 : template <class A, class P>
369 : void ArrayBase<A,P>::set_data(const size_type len,
370 : A* data,
371 788686 : const EnumDataOwned o)
372 : {
373 788686 : if (len == 0)
374 47365 : data = NULL;
375 :
376 788686 : P* share = next_share;
377 :
378 : // Set data and size of all subsequent elements.
379 :
380 788692 : for (; share; share = share->next_share)
381 : {
382 6 : share->Data = data;
383 6 : share->Len = len;
384 : }
385 :
386 : // Set data and size for all elements except first in the chain.
387 : // Leave share pointing to first in the chain.
388 :
389 791582 : for (share = (P*) this;
390 : true_pointer(share->prev_share);
391 : share = share->prev_share)
392 : {
393 2896 : share->Data = data;
394 2896 : share->Len = len;
395 : }
396 :
397 : // Free the old memory if necessary.
398 :
399 788686 : if ((share->Data != NULL) &&
400 : (share->Data != data) &&
401 : (share->prev_share == NULL))
402 213659 : delete [] share->Data;
403 :
404 : // Set the length and data for the first chain member.
405 :
406 788686 : share->Data = data;
407 788686 : share->Len = len;
408 :
409 : // Set the ownership flag
410 :
411 788686 : if (o == DataNotOwned)
412 0 : share->prev_share = special_not_owned_pointer();
413 : else
414 788686 : share->prev_share = NULL;
415 : }
416 :
417 :
418 : template <class A, class P>
419 59 : int ArrayBase<A,P>::nrefs() const
420 : {
421 59 : int n = 1;
422 : P* share;
423 81 : for (share = prev_share; true_pointer(share); share = share->prev_share)
424 22 : n++;
425 73 : for (share = next_share; share; share = share->next_share)
426 14 : n++;
427 59 : return n;
428 : }
429 :
430 :
431 : template <class A, class P>
432 0 : void ArrayBase<A,P>::debug_print(std::ostream& str,int max_elements)
433 : {
434 0 : str << "this=" << this;
435 0 : str << " size=" << size() << " Data=" << (void*) Data;
436 0 : str << " prev_share=" << prev_share;
437 0 : if (prev_share == special_not_owned_pointer())
438 0 : str << "(not owned flag)";
439 0 : str << " next_share=" << next_share << std::endl;
440 : //dump_data(str,max_elements);
441 : }
442 :
443 :
444 : /** Serialize an ArrayBase object. Note: as no one will ever create a
445 : * ArrayBase object, we will not bother to register this with the
446 : * Serializer().
447 : */
448 : template <class A, class P>
449 : int ArrayBase<A,P>::serializer( SerialObject::elementList_t& serial,
450 32 : Any& data, bool serialize )
451 : {
452 : ArrayBase<A,P>& tmp
453 32 : = const_cast<ArrayBase<A,P>&>(data.expose<ArrayBase<A,P> >());
454 :
455 32 : if ( ! serialize )
456 16 : tmp.resize(serial.size(), false);
457 :
458 32 : A* it = tmp.Data;
459 32 : size_t index = tmp.Len;
460 32 : int ans = 0;
461 88 : for ( ; index > 0; ++it, --index )
462 56 : if ( 0 != (ans = serial_transform(serial, *it, serialize)) )
463 0 : return ans;
464 :
465 32 : return 0;
466 : }
467 :
468 : } // namespace utilib
469 :
470 : #endif
|