1 #ifndef _ArrayPtrs_h_
2 #define _ArrayPtrs_h_
3 /* -------------------------------------------------------------------------- *
4 * OpenSim: ArrayPtrs.h *
5 * -------------------------------------------------------------------------- *
6 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
7 * See http://opensim.stanford.edu and the NOTICE file for more information. *
8 * OpenSim is developed at Stanford University and supported by the US *
9 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
10 * through the Warrior Web program. *
11 * *
12 * Copyright (c) 2005-2017 Stanford University and the Authors *
13 * Author(s): Frank C. Anderson *
14 * *
15 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
16 * not use this file except in compliance with the License. You may obtain a *
17 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
18 * *
19 * Unless required by applicable law or agreed to in writing, software *
20 * distributed under the License is distributed on an "AS IS" BASIS, *
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
22 * See the License for the specific language governing permissions and *
23 * limitations under the License. *
24 * -------------------------------------------------------------------------- */
25
26 /* Note: This code was originally developed by Realistic Dynamics Inc.
27 * Author: Frank C. Anderson
28 */
29
30
31 #include "osimCommonDLL.h"
32 #include <iostream>
33 #include "Exception.h"
34
35
36 //=============================================================================
37 //=============================================================================
38 /**
39 * A class for storing an array of pointers to objects of type T.
40 *
41 * In contrast to class Array<T>, when an object is added to this array
42 * a copy is not made. Rather, a pointer to the added object is
43 * stored in the array.
44 *
45 * When an ArrayPtrs object falls out of scope or is deleted, all objects
46 * pointed to by the pointers in the array are deleted unless the array
47 * is set not to own the memory associated with the objects to which its
48 * array points.
49 *
50 * The capacity of the class grows as needed. To use this template for a
51 * class of type T, class T should implement the following methods:
52 * default constructor, copy constructor, T* clone(),
53 * assignment operator (=), equality operator (==), less than
54 * operator (<), and the output operator (<<).
55 *
56 * @version 1.0
57 * @author Frank C. Anderson
58 */
59 namespace OpenSim {
60
61 template<class T> class ArrayPtrs
62 {
63 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
64 // DATA
65 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 protected:
67 /** Flag indicating whether this ArrayPtrs object is responsible for
68 (owns) the memory associated with the pointers in its array and therefore
69 should issue deletes for the pointers upon destruction. By default,
70 _memoryOwner = true. */
71 bool _memoryOwner;
72 /** Size of the array. Also the index of the first empty array element. */
73 int _size;
74 /** Current capacity of the array. */
75 int _capacity;
76 /** Increment by which the current capacity is increased when the capacity
77 of this array is reached. If negative, capacity doubles. */
78 int _capacityIncrement;
79 /** Array of pointers to objects of type T. */
80 T **_array;
81
82 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
83 // METHODS
84 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
85 //=============================================================================
86 // CONSTRUCTION
87 //=============================================================================
88 public:
89
90 // This typedef is used to avoid "duplicate const" errors with SWIG.
91 typedef typename std::add_const<T>::type ConstT;
92
93 //_____________________________________________________________________________
94 /**
95 * Destructor.
96 *
97 * When the array is deleted, if this array is the memory owner, pointers
98 * held by this array are also deleted.
99 *
100 * @see setMemoryOwner()
101 */
~ArrayPtrs()102 virtual ~ArrayPtrs()
103 {
104 if(_memoryOwner) clearAndDestroy();
105
106 // ARRAY
107 delete[] _array;
108 _array = NULL;
109 }
110 //_____________________________________________________________________________
111 /**
112 * Default constructor.
113 *
114 * @param aCapacity Initial capacity of the array. The capacity
115 * must be 1 or greater.
116 */
117 explicit ArrayPtrs(int aCapacity=1)
118 {
119 setNull();
120
121 // CAPACITY
122 if(aCapacity<1) aCapacity = 1;
123 ensureCapacity(aCapacity);
124
125 }
126 //_____________________________________________________________________________
127 /**
128 * Copy constructor.
129 *
130 * @param aArray Array to be copied.
131 */
ArrayPtrs(const ArrayPtrs<T> & aArray)132 ArrayPtrs(const ArrayPtrs<T> &aArray)
133 {
134 setNull();
135 *this = aArray;
136 }
137
138
139 private:
140 //_____________________________________________________________________________
141 /**
142 * %Set all member variables to their null or default values.
143 */
setNull()144 void setNull()
145 {
146 _memoryOwner = true;
147 _size = 0;
148 _capacityIncrement = -1;
149 _capacity = 0;
150 _array = NULL;
151 }
152
153 public:
154 //_____________________________________________________________________________
155 /**
156 * Destroy all objects pointed to by this array and set the size of the
157 * array to zero. When this method is called, the objects pointed to by
158 * this array are destroyed (deleted) even if this array is not set as
159 * the memory owner.
160 *
161 * @see setMemoryOwner()
162 */
clearAndDestroy()163 void clearAndDestroy()
164 {
165 if(_array==NULL) return;
166
167 int i;
168 for(i=0;i<_size;i++) {
169 delete _array[i]; _array[i]=NULL;
170 }
171
172 _size = 0;
173 }
174
175
176 //=============================================================================
177 // OPERATORS
178 //=============================================================================
179 public:
180 //-----------------------------------------------------------------------------
181 // ASSIGNMENT (=)
182 //-----------------------------------------------------------------------------
183 //_____________________________________________________________________________
184 /**
185 * Assign this array to a specified array.
186 * This operator makes a complete copy of the specified array; all member
187 * variables and objects in the array are copied. Because all objects are
188 * copied, this object takes ownership of the newly allocated objects (i.e.,
189 * _memoryOwner is set to true. So, the result is two independent,
190 * identical arrays, with the possible exception of the _memoryOwner flag.
191 *
192 * @param aArray Array to be copied.
193 * @return Reference to this array.
194 */
195 #ifndef SWIG
196 ArrayPtrs<T>& operator=(const ArrayPtrs<T> &aArray)
197 {
198 // DELETE OLD ARRAY
199 if(_memoryOwner) clearAndDestroy();
200
201 // COPY MEMBER VARIABLES
202 _size = aArray._size;
203 _capacity = aArray._capacity;
204 _capacityIncrement = aArray._capacityIncrement;
205
206 // ARRAY
207 int i;
208 if(_array!=NULL) delete[] _array;
209 _array = new T*[_capacity];
210 for(i=0;i<_size;i++) {
211 if(aArray._array[i]!=NULL) _array[i] = aArray._array[i]->clone();
212 }
213
214 // TAKE OWNERSHIP OF MEMORY
215 _memoryOwner = true;
216
217 return(*this);
218 }
219
220 //-----------------------------------------------------------------------------
221 // EQUALITY (==)
222 //-----------------------------------------------------------------------------
223 //_____________________________________________________________________________
224 /**
225 * Determine if two arrays are equal.
226 *
227 * Two arrays are equal if their contents are equal. That is, each array
228 * must be the same length and their corresponding array elements must be
229 * equal.
230 *
231 * @param aArray Array to be tested as equal.
232 * @return True if equal, false if not equal.
233 */
234 bool operator==(const ArrayPtrs<T> &aArray) const
235 {
236 if(_size != aArray._size) return(false);
237
238 int i;
239 for(i=0;i<_size;i++) {
240 if( !(_array[i]==aArray._array[i]) ) return(false);
241 }
242
243 return(true);
244 }
245
246 //-----------------------------------------------------------------------------
247 // BRACKETS ([])
248 //-----------------------------------------------------------------------------
249 //_____________________________________________________________________________
250 /**
251 * Get a pointer to the array object at a specified index.
252 *
253 * This operator is intended for accessing array elements with as little
254 * overhead as possible, so no error checking is performed.
255 * The caller must make sure the specified index is within the bounds of
256 * the array. If error checking is desired, use ArrayPtrs::get().
257 *
258 * @param aIndex Index of the desired element (0 <= aIndex < _size).
259 * @return Reference to the array element.
260 * @throws Exception if a NULL pointer is encountered.
261 * @see get().
262 */
263 T* operator[](int aIndex) const
264 {
265 return( _array[aIndex] );
266 }
267 //_____________________________________________________________________________
268 //-----------------------------------------------------------------------------
269 // OUTPUT (<<)
270 //-----------------------------------------------------------------------------
271 //_____________________________________________________________________________
272 /**
273 * Implementation of the output operator.
274 * The output for an array looks like the following:\n\n
275 *
276 * ArrayPtrs[size] = T[0] T[1] T[2] ... T[size-1].
277 *
278 * @param aOut Output stream.
279 * @param aArray Array to be output.
280 * @return Reference to the output stream.
281 */
282 friend std::ostream& operator<<(std::ostream &aOut,const ArrayPtrs<T> &aArray)
283 {
284 aOut << "ArrayPtrs[" << aArray.getSize() <<"] =";
285
286 int i;
287 T* obj;
288 for(i=0;i<aArray.getSize();i++) {
289 aOut << " ";
290 obj = aArray[i];
291 if(obj==NULL) {
292 aOut << "NULL";
293 } else {
294 // The following line is having trouble compiling on IRIX.
295 //aOut << *obj;
296 }
297 }
298
299 return(aOut);
300 }
301
302
303 //=============================================================================
304 // MEMORY OWNERSHIP
305 //=============================================================================
306 //_____________________________________________________________________________
307 /**
308 * %Set whether or not this array owns the memory pointed to by the pointers
309 * in its array.
310 *
311 * @param aTrueFalse If true, all the memory associated with each of the
312 * pointers in this array are deleted upon the array's destruction. If
313 * false, deletes are not issued for each of the pointers.
314 */
setMemoryOwner(bool aTrueFalse)315 void setMemoryOwner(bool aTrueFalse)
316 {
317 _memoryOwner = aTrueFalse;
318 }
319 //_____________________________________________________________________________
320 /**
321 * Get whether or not this array owns the memory pointed to by the pointers
322 * in its array.
323 *
324 * If the array is set to own the memory pointed to by its pointers, this
325 * array issues deletes for all these pointers upon the array's destruction.
326 * If not, this array does not issue deletes.
327 *
328 * @return True if this array owns the memory; false otherwise.
329 */
getMemoryOwner()330 bool getMemoryOwner() const
331 {
332 return(_memoryOwner);
333 }
334
335
336 //=============================================================================
337 // CAPACITY
338 //=============================================================================
339 //_____________________________________________________________________________
340 /**
341 * Compute a new capacity that is at least as large as a specified minimum
342 * capacity; this method does not change the capacity, it simply computes
343 * a new recommended capacity.
344 *
345 * If the capacity increment is negative, the current capacity is
346 * doubled until the computed capacity is greater than or equal to the
347 * specified minimum capacity. If the capacity increment is positive, the
348 * current capacity increments by this amount until the computed capacity is
349 * greater than or equal to the specified minimum capacity. If the capacity
350 * increment is zero, the computed capacity is set to the current capacity
351 * and false is returned.
352 *
353 * @param rNewCapacity New computed capacity.
354 * @param aMinCapacity Minimum new computed capacity. The computed capacity
355 * is incremented until it is at least as large as aMinCapacity, assuming
356 * the capacity increment is not zero.
357 * @return True if the new capacity was increased, false otherwise (i.e.,
358 * if the capacity increment is set to 0).
359 * @see setCapacityIncrement()
360 */
computeNewCapacity(int aMinCapacity,int & rNewCapacity)361 bool computeNewCapacity(int aMinCapacity,int &rNewCapacity)
362 {
363 rNewCapacity = _capacity;
364 if(rNewCapacity < 1) rNewCapacity = 1;
365
366 // CHECK FOR ZERO INCREMENT
367 if(_capacityIncrement == 0) {
368 std::cout << "ArrayPtrs.computeNewCapacity: WARN- capacity is set";
369 std::cout << " not to increase (i.e., _capacityIncrement==0).\n";
370 return(false);
371 }
372
373 // INCREMENT UNTIL LARGER THAN THE MINIMUM SIZE
374 while(rNewCapacity < aMinCapacity) {
375 if(_capacityIncrement < 0) {
376 rNewCapacity = 2 * rNewCapacity;
377 } else {
378 rNewCapacity = rNewCapacity + _capacityIncrement;
379 }
380 }
381
382 return(true);
383 }
384 //_____________________________________________________________________________
385 /**
386 * Ensure that the capacity of this array is at least the specified amount.
387 * The newly allocated array elements are initialized to NULL.
388 *
389 * @param aCapacity Desired capacity.
390 * @return true if the capacity was successfully obtained, false otherwise.
391 */
ensureCapacity(int aCapacity)392 bool ensureCapacity(int aCapacity)
393 {
394 // CHECK REQUESTED CAPACITY
395 if(aCapacity < 1) aCapacity = 1;
396 if(_capacity>=aCapacity) return(true);
397
398 // ALLOCATE THE NEW ARRAY
399 int i;
400 T **newArray = new T*[aCapacity];
401 if(newArray==NULL) {
402 std::cout << "ArrayPtrs.ensureCapacity: ERR- failed to increase capacity.\n";
403 return(false);
404 }
405
406 // COPY CURRENT ARRAY
407 if(_array!=NULL) {
408 for(i=0;i<_size;i++) newArray[i] = _array[i];
409 for(i=_size;i<aCapacity;i++) newArray[i] = NULL;
410 delete[] _array;
411 } else {
412 for(i=0;i<aCapacity;i++) newArray[i] = NULL;
413 }
414
415 // REASSIGN
416 _capacity = aCapacity;
417 _array = newArray;
418
419 return(true);
420 }
421
422 //_____________________________________________________________________________
423 /**
424 * Trim the capacity of this array so that it is one larger than the size
425 * of this array. This is useful for reducing the amount of memory used
426 * by this array. This capacity is kept at one larger than the size so
427 * that, for example, an array of characters can be treated as a NULL
428 * terminated string.
429 */
trim()430 void trim()
431 {
432 // COMPUTE NEW CAPACITY
433 int newCapacity = _size + 1;
434 if(newCapacity>=_capacity) return;
435 if(newCapacity<1) newCapacity = 1;
436
437 // TEMPORARY ARRAY
438 T **array = _array;
439
440 // ALLOCATE NEW ARRAY
441 _array = new T*[newCapacity];
442 if(_array==NULL) {
443 std::cout << "ArrayPtrs.trim: ERR- unable to allocate array.\n";
444 return;
445 }
446
447 // RESET PREVIOUS VALUES
448 int i;
449 for(i=0;i<_size;i++) _array[i] = array[i];
450 _array[_size] = NULL;
451
452 // SET CORRECT CAPACITY
453 _capacity = newCapacity;
454
455 // DELETE OLD ARRAY
456 delete[] array;
457 }
458 //_____________________________________________________________________________
459 /**
460 * Get the capacity of this storage instance.
461 */
getCapacity()462 int getCapacity() const
463 {
464 return(_capacity);
465 }
466
467 //-----------------------------------------------------------------------------
468 // CAPACITY INCREMENT
469 //-----------------------------------------------------------------------------
470 //_____________________________________________________________________________
471 /**
472 * %Set the amount by which the capacity is increased when the capacity of
473 * of the array in exceeded.
474 * If the specified increment is negative or this method
475 * is called with no argument, the capacity is set to double whenever
476 * the capacity is exceeded.
477 *
478 * @param aIncrement Desired capacity increment.
479 */
setCapacityIncrement(int aIncrement)480 void setCapacityIncrement(int aIncrement)
481 {
482 _capacityIncrement = aIncrement;
483 }
484 //_____________________________________________________________________________
485 /**
486 * Get the amount by which the capacity is increased.
487 */
getCapacityIncrement()488 int getCapacityIncrement() const
489 {
490 return(_capacityIncrement);
491 }
492 #endif
493 //=============================================================================
494 // STORAGE OPERATIONS
495 //=============================================================================
496 //-----------------------------------------------------------------------------
497 // SIZE
498 //-----------------------------------------------------------------------------
499 //_____________________________________________________________________________
500 /**
501 * %Set the size of the array. This method can be used only to decrease
502 * the size of the array. If the size of an array is decreased, all objects
503 * in the array that become invalid as a result of the decrease are
504 * deleted.
505 *
506 * Note that the size of an array is different than its capacity. The size
507 * indicates how many valid elements are stored in an array. The capacity
508 * indicates how much the size of the array can be increased without
509 * allocated more memory. At all times size <= capacity.
510 *
511 * @param aSize Desired size of the array. The size must be greater than
512 * or equal to zero and less than or equal to the current size of the
513 * array.
514 * @return True if the requested size change was carried out, false
515 * otherwise.
516 */
setSize(int aSize)517 bool setSize(int aSize)
518 {
519 if(aSize==_size) return(true);
520 if(aSize>_size) return(false);
521 if(aSize<0) aSize = 0;
522 if(aSize<_size) {
523 int i;
524 for(i=(_size-1);i>=aSize;i--) {
525 if(_array[i]!=NULL) {
526 if(getMemoryOwner()) { delete _array[i]; }
527 _array[i] = NULL;
528 }
529 }
530 _size = aSize;
531 }
532
533 return(true);
534 }
535 //_____________________________________________________________________________
536 /**
537 * Get the size of the array.
538 *
539 * @return Size of the array.
540 */
getSize()541 int getSize() const
542 {
543 return(_size);
544 }
545
546 /** Alternate name for getSize(). **/
size()547 int size() const {return getSize();}
548
549 //-----------------------------------------------------------------------------
550 // INDEX
551 //-----------------------------------------------------------------------------
552 //_____________________________________________________________________________
553 /**
554 * Get the index of an object by specifying its name.
555 *
556 * @param aObject Address of the object whose index is sought.
557 * @param aStartIndex Index at which to start searching. If the object is
558 * not found at or following aStartIndex, the array is searched from
559 * its beginning.
560 * @return Index of the object with the address aObject. If no such object
561 * exists in the array, -1 is returned.
562 */
563 int getIndex(ConstT *aObject,int aStartIndex=0) const
564 {
565 if(aStartIndex<0) aStartIndex=0;
566 if(aStartIndex>=getSize()) aStartIndex=0;
567
568 // SEARCH STARTING FROM aStartIndex
569 int i;
570 for(i=aStartIndex;i<getSize();i++) {
571 if(_array[i] == aObject) return(i);
572 }
573
574 // SEARCH FROM BEGINNING
575 for(i=0;i<aStartIndex;i++) {
576 if(_array[i] == aObject) return(i);
577 }
578
579 return(-1);
580 }
581 //_____________________________________________________________________________
582 /**
583 * Get the index of an object by specifying its name.
584 *
585 * @param aName Name of the object whose index is sought.
586 * @param aStartIndex Index at which to start searching. If the object is
587 * not found at or following aStartIndex, the array is searched from
588 * its beginning.
589 * @return Index of the object named aName. If no such object exists in
590 * the array, -1 is returned.
591 */
592 int getIndex(const std::string &aName,int aStartIndex=0) const
593 {
594 if(aStartIndex<0) aStartIndex=0;
595 if(aStartIndex>=getSize()) aStartIndex=0;
596
597 // SEARCH STARTING FROM aStartIndex
598 int i;
599 for(i=aStartIndex;i<getSize();i++) {
600 if(_array[i]->getName() == aName) return(i);
601 }
602
603 // SEARCH FROM BEGINNING
604 for(i=0;i<aStartIndex;i++) {
605 if(_array[i]->getName() == aName) return(i);
606 }
607
608 return(-1);
609 }
610
611 //-----------------------------------------------------------------------------
612 // APPEND
613 //-----------------------------------------------------------------------------
614 //_____________________________________________________________________________
615 /**
616 * Append to the array. A copy of the specified object is NOT made.
617 *
618 * @param aObject Object to be appended.
619 * @return True if the append was successful, false otherwise.
620 */
append(T * aObject)621 bool append(T *aObject)
622 {
623 if(aObject==NULL) {
624 std::cout<<"ArrayPtrs.append: ERR- NULL pointer."<<std::endl;
625 return(false);
626 }
627
628 // ENSURE CAPACITY
629 if((_size+1)>=_capacity) {
630 int newCapacity;
631 bool success;
632 success = computeNewCapacity(_size+1,newCapacity);
633 if(!success) return(success);
634 success = ensureCapacity(newCapacity);
635 if(!success) return(success);
636 }
637
638 // SET
639 _array[_size] = aObject;
640 _size++;
641
642 return(true);
643 }
644 //_____________________________________________________________________________
645 /**
646 * Append an array of objects. Copies of the objects are NOT made
647 *
648 * @param aArray Array of objects to be appended.
649 * @return True if the append was successful, false otherwise.
650 */
append(ArrayPtrs<T> & aArray)651 bool append(ArrayPtrs<T> &aArray)
652 {
653 // LOOP THROUGH THE ELEMENTS
654 bool success;
655 int i,n=aArray.getSize();
656 for(i=0;i<n;i++) {
657 success = append(aArray[i]);
658 if(!success) return(success);
659 }
660
661 return(true);
662 }
663
664 //-----------------------------------------------------------------------------
665 // INSERT
666 //-----------------------------------------------------------------------------
667 //_____________________________________________________________________________
668 /**
669 * Insert an object into the array at a specified index. A copy of the
670 * specified object is NOT made.
671 *
672 * This method is relatively computationally costly since many of the array
673 * elements may need to be shifted.
674 *
675 * @param aObject Object to be inserted.
676 * @param aIndex Index at which to insert the new object. All current elements
677 * from aIndex to the end of the array are shifted one place in the direction
678 * of the end of the array. The specified index must be less than or
679 * equal to the size of the array. Note that if aIndex is equal to the
680 * size of the array, the insertion is equivalent to an append.
681 * @return True if the insertion was successful, false otherwise.
682 */
insert(int aIndex,T * aObject)683 bool insert(int aIndex,T *aObject)
684 {
685 // NULL POINTER
686 if(aObject==NULL) {
687 std::cout<<"ArrayPtrs.insert: ERR- NULL pointer."<<std::endl;
688 return(false);
689 }
690
691 // NEGATIVE INDEX
692 if(aIndex<0) {
693 std::cout << "ArrayPtrs.insert: ERR- aIndex was less than 0.\n";
694 return(false);
695 }
696
697 // INDEX PAST END OF ARRAY
698 if(aIndex>_size) {
699 return(false);
700 }
701
702 // ENSURE CAPACITY
703 if((_size+1)>=_capacity) {
704 int newCapacity;
705 bool success;
706 success = computeNewCapacity(_size+1,newCapacity);
707 if(!success) return(success);
708 success = ensureCapacity(newCapacity);
709 if(!success) return(success);
710 }
711
712 // SHIFT ARRAY
713 int i;
714 for(i=_size;i>aIndex;i--) {
715 _array[i] = _array[i-1];
716 }
717
718 // SET
719 _array[aIndex] = aObject;
720 _size++;
721
722 return(true);
723 }
724
725 //-----------------------------------------------------------------------------
726 // REMOVE
727 //-----------------------------------------------------------------------------
728 //_____________________________________________________________________________
729 /**
730 * Remove an object from the array at a specified index.
731 * The object is deleted when it is removed.
732 *
733 * This method is relatively computationally costly since many of the array
734 * elements may need to be shifted.
735 *
736 * @param aIndex Index of the value to remove. All elements from aIndex to
737 * the end of the array are shifted one place toward the beginning of
738 * the array. If aIndex is less than 0 or greater than or equal to the
739 * current size of the array, no element is removed.
740 * @return True if the removal was successful, false otherwise.
741 */
remove(int aIndex)742 bool remove(int aIndex)
743 {
744 if(aIndex<0) {
745 return(false);
746 }
747 if(aIndex>=_size) {
748 return(false);
749 }
750
751 // DELETE CURRENT OBJECT
752 if(getMemoryOwner()&&(_array[aIndex]!=NULL)) delete _array[aIndex];
753
754 // SHIFT ARRAY
755 int i;
756 _size--;
757 for(i=aIndex;i<_size;i++) {
758 _array[i] = _array[i+1];
759 }
760 _array[_size] = NULL;
761
762 return(true);
763 }
764 //_____________________________________________________________________________
765 /**
766 * Remove an object from the array by specifying its address.
767 * If this array is set as the memory owner, the object is deleted when it
768 * is removed.
769 *
770 * This method is relatively computationally costly since many of the array
771 * elements may need to be shifted.
772 *
773 * @param aObject Pointer to the object to be removed. If an object with the
774 * specified address is not found, no action is taken.
775 * @return True if the removal was successful, false otherwise.
776 */
remove(ConstT * aObject)777 bool remove(ConstT* aObject)
778 {
779 int index = getIndex(aObject);
780 return( remove(index) );
781 }
782
783
784 //-----------------------------------------------------------------------------
785 // SET AND GET
786 //-----------------------------------------------------------------------------
787 //_____________________________________________________________________________
788 /**
789 * %Set the object at a specified index. A copy of the object is NOT made.
790 *
791 * If the set method is successful and the array is set as the memory
792 * owner, the previous object stored at the specified index is deleted.
793 *
794 * @param aIndex Index of the array element to be set. aIndex must be
795 * greater than zero and less than or equal to the size of the array. Note
796 * that if aIndex is equal to the size of the array, the set is equivalent
797 * to an append.
798 * @param aObject Object to be set.
799 * @return True if the set was successful, false otherwise.
800 * @see setMemoryOwner()
801 */
set(int aIndex,T * aObject)802 bool set(int aIndex,T *aObject)
803 {
804 if(aIndex<0) return(false);
805 if(aIndex>_size) return(false);
806
807 // APPEND
808 if(aIndex==_size) {
809 bool success;
810 success = append(aObject);
811 return(success);
812 }
813
814 // SET
815 if(getMemoryOwner() && (_array[aIndex]!=NULL)) delete _array[aIndex];
816 _array[aIndex] = aObject;
817
818 return(true);
819 }
820 //_____________________________________________________________________________
821 /**
822 * Get the object at a specified array index.
823 *
824 * If the index is negative or passed the end of the array, an exception
825 * is thrown.
826 *
827 * For faster execution, the array elements can be accessed through the
828 * overloaded operator[], which does no bounds checking.
829 *
830 * @param aIndex Array index of the desired object.
831 * @return Pointer to the desired object.
832 * @throws Exception if (aIndex<0)||(aIndex>=_size) or if the pointer
833 * at aIndex is NULL.
834 * @see operator[].
835 */
get(int aIndex)836 T* get(int aIndex)
837 {
838 if((aIndex<0)||(aIndex>=_size)) {
839 throw(Exception("ArrayPtrs.get: Array index out of bounds."));
840 }
841 if(_array[aIndex]==NULL) {
842 throw(Exception("ArrayPtrs.get: NULL pointer.",
843 __FILE__,__LINE__));
844 }
845
846 return(_array[aIndex]);
847 }
848 //_____________________________________________________________________________
849 /**
850 * Get the object at a specified array index.
851 *
852 * If the index is negative or passed the end of the array, an exception
853 * is thrown.
854 *
855 * For faster execution, the array elements can be accessed through the
856 * overloaded operator[], which does no bounds checking.
857 *
858 * @param aIndex Array index of the desired object.
859 * @return Pointer to the desired object.
860 * @throws Exception if (aIndex<0)||(aIndex>=_size) or if the pointer
861 * at aIndex is NULL.
862 * @see operator[].
863 */
864 #ifndef SWIG
get(int aIndex)865 const T* get(int aIndex) const
866 {
867 if((aIndex<0)||(aIndex>=_size)) {
868 throw(Exception("ArrayPtrs.get: Array index out of bounds."));
869 }
870 if(_array[aIndex]==NULL) {
871 throw(Exception("ArrayPtrs.get: NULL pointer.",
872 __FILE__,__LINE__));
873 }
874
875 return(_array[aIndex]);
876 }
877 #endif
878 //_____________________________________________________________________________
879 /**
880 * Get the first object that has a specified name.
881 *
882 * If the array doesn't contain an object of the specified name, an
883 * exception is thrown.
884 *
885 * @param aName Name of the desired object.
886 * @return Pointer to the object.
887 * @throws Exception if no such object exists.
888 * @see getIndex()
889 */
get(const std::string & aName)890 T* get(const std::string &aName)
891 {
892 int index = getIndex(aName);
893 if(index==-1) {
894 std::string msg = "ArrayPtrs.get(aName): No object with name ";
895 msg += aName;
896 throw( Exception(msg,__FILE__,__LINE__) );
897 }
898 return(_array[index]);
899 }
900 //_____________________________________________________________________________
901 /**
902 * Get the first object that has a specified name.
903 *
904 * If the array doesn't contain an object of the specified name, an
905 * exception is thrown.
906 *
907 * @param aName Name of the desired object.
908 * @return Pointer to the object.
909 * @throws Exception if no such object exists.
910 * @see getIndex()
911 */
912 #ifndef SWIG
get(const std::string & aName)913 const T* get(const std::string &aName) const
914 {
915 int index = getIndex(aName);
916 if(index==-1) {
917 std::string msg = "ArrayPtrs.get(aName): No object with name ";
918 msg += aName;
919 throw( Exception(msg,__FILE__,__LINE__) );
920 }
921 return(_array[index]);
922 }
923 #endif
924 //_____________________________________________________________________________
925 /**
926 * Get the last value in the array.
927 *
928 * @return Last value in the array.
929 * @throws Exception if the array is empty.
930 */
getLast()931 T* getLast() const
932 {
933 if(_size<=0) {
934 throw(Exception("Array is empty."));
935 }
936 return(_array[_size-1]);
937 }
938
939
940 //=============================================================================
941 // SEARCH
942 //=============================================================================
943 //_____________________________________________________________________________
944 /**
945 * Search for the largest value in the array that is less than or
946 * equal to a specified value. If there is more than one element with this
947 * largest value, the index of the first of these elements can optionally be
948 * found, but this can be up to twice as costly.
949 *
950 * This method assumes that the array element values monotonically
951 * increase as the array index increases. Note that monotonically
952 * increase means never decrease, so it is permissible for adjacent elements
953 * to have the same value.
954 *
955 * A binary search is performed (i.e., the array is repeatedly subdivided
956 * into two bins one of which must contain the specified until the
957 * appropriate element is identified), so the performance of this method
958 * is approximately ln(n), where n is the size of the array.
959 *
960 * @param aValue Value to which the array elements are compared.
961 * @param aFindFirst If true, find the first element that satisfies
962 * the search. If false, the index of any element that satisfies the
963 * search can be returned- which index will be returned depends on the
964 * length of the array and is therefore somewhat arbitrary. By default,
965 * this flag is false.
966 * @param aLo Lowest array index to consider in the search.
967 * @param aHi Highest array index to consider in the search.
968 * @return Index of the array element that has the largest value that is less
969 * than or equal to aValue. If there is more than one such elements with the
970 * same value and aFindFirst is set to true, the index of the first of
971 * these elements is returned. If an error is encountered (e.g., the array
972 * is empty), or the array contains no element that is less than or equal
973 * to aValue, -1 is returned.
974 */
975 int searchBinary(ConstT& aObject,bool aFindFirst=false,
976 int aLo=-1,int aHi=-1) const
977 {
978 if(_size<=0) return(-1);
979 int lo = aLo; if(lo<0) lo = 0;
980 int hi = aHi; if((hi<0)||(hi>=_size)) hi = _size - 1;
981 int mid = -1;
982
983 // CHECK lo AND hi
984 if(lo>hi) return(-1);
985
986 // SEARCH
987 while(lo <= hi) {
988 mid = (lo + hi) / 2;
989 if(aObject < *_array[mid]) {
990 hi = mid - 1;
991 } else if(*_array[mid] < aObject) {
992 lo = mid + 1;
993 } else {
994 break;
995 }
996 }
997
998 // MAKE SURE LESS THAN
999 if(aObject < *_array[mid]) mid--;
1000 if(mid<=0) {
1001 return(mid);
1002 }
1003
1004 // FIND FIRST
1005 if(aFindFirst) {
1006 if(*_array[mid-1]<*_array[mid]) {
1007 return(mid);
1008 }
1009 lo = aLo; if(lo<0) lo = 0;
1010 hi = mid;
1011 int mid2 = mid;
1012 T *obj2 = _array[mid];
1013 while(lo <= hi) {
1014 mid2 = (lo + hi) / 2;
1015 if(*_array[mid2] == *obj2) {
1016 hi = mid2 - 1;
1017 } else if(*_array[mid2] < *obj2) {
1018 lo = mid2 + 1;
1019 }
1020 }
1021 if(*_array[mid2] < *obj2) mid2++;
1022 if(mid2<mid) mid = mid2;
1023 }
1024
1025 return(mid);
1026 }
1027
1028 //=============================================================================
1029 }; // END of class ArrayPtrs
1030
1031 }; //namespace
1032 //=============================================================================
1033 //=============================================================================
1034
1035
1036 #endif //__ArrayPtrs_h__
1037