1 /* 2 * Copyright 2006 Sony Computer Entertainment Inc. 3 * 4 * Licensed under the MIT Open Source License, for details please see license.txt or the website 5 * http://www.opensource.org/licenses/mit-license.php 6 * 7 */ 8 9 #ifndef __DAE_ARRAY_H__ 10 #define __DAE_ARRAY_H__ 11 #include <new> 12 #include <dae/daeMemorySystem.h> 13 14 class daeAtomicType; 15 16 /** 17 * COLLADA C++ class that implements storage for resizable array containers. 18 */ 19 class daeArray 20 { 21 protected: 22 size_t _count; 23 size_t _capacity; 24 daeMemoryRef _data; 25 size_t _elementSize; 26 daeAtomicType* _type; 27 public: 28 /** 29 * Constructor 30 */ 31 DLLSPEC daeArray(); 32 /** 33 * Destructor 34 */ 35 virtual DLLSPEC ~daeArray(); 36 /** 37 * Clears the contents of the array. Do not use this function if the array contains @c daeSmartRef objects and the 38 * @c dom* class the array belongs to has a @c _contents member. 39 * 40 * Many @c dom* objects have a @c _contents member that stores the original creation order of the @c daeElements 41 * that are their children. If you use @c clear() on a @c daeArray of @c daeSmartRef derived objects, these 42 * objects will not be removed from @c _contents, which can cause problems when you 43 * save the data. We recommended that @c clear() not be used on arrays that are part of a @c dom* object. 44 */ 45 virtual DLLSPEC void clear() = 0; 46 /** 47 * Sets the size of an element in the array. This clears and reinitializes the array. 48 * @param elementSize Size of an element in the array. 49 */ 50 DLLSPEC void setElementSize(size_t elementSize); 51 /** 52 * Gets the size of an element in this array. 53 * @return Returns the size of an element in this array. 54 */ 55 size_t getElementSize() const {return _elementSize;} 56 /** 57 * Grows the array to the specified size and sets the @c daeArray to that size. 58 * @param cnt Size to grow the array to. 59 */ 60 virtual void setCount(size_t cnt) = 0; 61 /** 62 * Gets the number of items stored in this @c daeArray. 63 * @return Returns the number of items stored in this @c daeArray. 64 */ 65 size_t getCount() const {return _count;} 66 /** 67 * Increases the capacity of the @c daeArray. 68 * @param minCapacity The minimum array capacity (the actual resulting capacity may be higher). 69 */ 70 virtual void grow(size_t minCapacity) = 0; 71 /** 72 * Gets the current capacity of the array, the biggest it can get without incurring a realloc. 73 * @return Returns the capacity of the array. 74 */ 75 size_t getCapacity() const {return _capacity;} 76 /** 77 * Gets a pointer to the raw memory of a particular element. 78 * @return Returns a pointer to the memory for the raw data. 79 */ 80 daeMemoryRef getRaw(size_t index) const {return _data + index*_elementSize;} 81 /** 82 * Removes an item at a specific index in the @c daeArray. 83 * @param index Index number of the item to delete. 84 * @return Returns DAE_OK if success, a negative value defined in daeError.h otherwise. 85 * @note The @c daeElement objects sometimes list 86 * objects in two places, the class member and the <i> @c _contents </i> array, when you remove something from the 87 * dom, you must remove it from both places. 88 */ 89 virtual daeInt removeIndex(size_t index) = 0; 90 91 // Provided for backward compatibility only. Don't use these. 92 void setRawCount(size_t cnt) { setCount(cnt); } // Use setCount instead 93 daeMemoryRef getRawData() const {return _data;} // Use getRaw instead 94 }; 95 96 /** 97 * COLLADA C++ templated version of @c daeArray for storing items of various types. 98 */ 99 template <class T> 100 class daeTArray : public daeArray 101 { 102 protected: 103 T* prototype; 104 public: 105 /** 106 * Constructor. 107 */ 108 daeTArray() { 109 _elementSize = sizeof( T ); 110 prototype = NULL; 111 } 112 /** 113 * Constructor. 114 */ 115 explicit daeTArray(T* prototype) : prototype(prototype) { 116 _elementSize = sizeof( T ); 117 } 118 /** 119 * Copy Constructor 120 */ 121 daeTArray( const daeTArray<T> &cpy ) : daeArray() { 122 prototype = NULL; 123 *this = cpy; 124 } 125 /** 126 * Constructor that takes one element and turns into an array 127 */ 128 explicit daeTArray( const T &el ) { 129 _elementSize = sizeof(T); 130 prototype = NULL; 131 append( el ); 132 } 133 /** 134 * Destructor. 135 */ 136 virtual ~daeTArray() { 137 clear(); 138 delete prototype; 139 } 140 /** 141 * Frees the memory in this array and resets it to it's initial state. 142 */ 143 virtual void clear() 144 { 145 for(size_t i=0;i<_count;i++) 146 ((T*)_data + i)->~T(); 147 free(_data); 148 _count = 0; 149 _capacity = 0; 150 _data = NULL; 151 } 152 153 /** 154 * Increases the capacity of the @c daeArray. 155 * @param minCapacity The minimum array capacity (the actual resulting capacity may be higher). 156 */ 157 void grow(size_t minCapacity) { 158 if (minCapacity <= _capacity) 159 return; 160 161 size_t newCapacity = _capacity == 0 ? 1 : _capacity; 162 while(newCapacity < minCapacity) 163 newCapacity *= 2; 164 165 T* newData = (T*)malloc(newCapacity*_elementSize); 166 for (size_t i = 0; i < _count; i++) { 167 new (&newData[i]) T(get(i)); 168 ((T*)_data + i)->~T(); 169 } 170 171 if (_data != NULL) 172 free(_data); 173 174 _data = (daeMemoryRef)newData; 175 _capacity = newCapacity; 176 } 177 178 /** 179 * Removes an item at a specific index in the @c daeArray. 180 * @param index Index number of the item to delete. 181 * @return Returns DAE_OK if success, a negative value defined in daeError.h otherwise. 182 * @note The @c daeElement objects sometimes list 183 * objects in two places, the class member and the <i> @c _contents </i> array, when you remove something from the 184 * dom, you must remove it from both places. 185 */ 186 virtual daeInt removeIndex(size_t index) 187 { 188 if (index >= _count) 189 return(DAE_ERR_INVALID_CALL); 190 191 for (size_t i = index; i < _count-1; i++) 192 *((T*)_data+i) = *((T*)_data+i+1); 193 ((T*)_data+(_count-1))->~T(); 194 _count--; 195 return DAE_OK; 196 } 197 198 /** 199 * Resets the number of elements in the array. If the array increases in size, the new 200 * elements will be initialized to the specified value. 201 * @param nElements The new size of the array. 202 * @param value The value new elements will be initialized to. 203 * @note Shrinking the array does NOT free up memory. 204 */ 205 void setCount(size_t nElements, const T& value) 206 { 207 grow(nElements); 208 // Destruct the elements that are being chopped off 209 for (size_t i = nElements; i < _count; i++) 210 ((T*)_data+i)->~T(); 211 // Use value to initialize the new elements 212 for (size_t i = _count; i < nElements; i++) 213 new ((void*)((T*)_data+i)) T(value); 214 _count = nElements; 215 } 216 217 /** 218 * Resets the number of elements in the array. If the array increases in size, the new 219 * elements will be initialized with a default constructor. 220 * @param nElements The new size of the array. 221 * @note Shrinking the array does NOT free up memory. 222 */ 223 virtual void setCount(size_t nElements) { 224 if (prototype) 225 setCount(nElements, *prototype); 226 else 227 setCount(nElements, T()); 228 } 229 230 /** 231 * Sets a specific index in the @c daeArray, growing the array if necessary. 232 * @param index Index of the object to set, asserts if the index is out of bounds. 233 * @param value Value to store at index in the array. 234 */ 235 void set(size_t index, const T& value) { 236 if (index >= _count) 237 setCount(index+1); 238 ((T*)_data)[index] = value; 239 } 240 241 /** 242 * Gets the object at a specific index in the @c daeArray. 243 * @param index Index of the object to get, asserts if the index is out of bounds. 244 * @return Returns the object at index. 245 */ 246 T& get(size_t index) { 247 assert(index < _count); 248 return ((T*)_data)[index]; } 249 /** 250 * Gets the object at a specific index in the @c daeArray. 251 * @param index Index of the object to get, asserts if the index is out of bounds. 252 * @return Returns the object at index. 253 */ 254 const T& get(size_t index) const { 255 assert(index < _count); 256 return ((T*)_data)[index]; } 257 258 /** 259 * Appends a new object to the end of the @c daeArray. 260 * @param value Value of the object to append. 261 * @return Returns the index of the new object. 262 */ 263 size_t append(const T& value) { 264 set(_count, value); 265 return _count-1; 266 } 267 268 /** 269 * Appends a unique object to the end of the @c daeArray. 270 * Functions the same as @c append(), but does nothing if the value is already in the @c daeArray. 271 * @param value Value of the object to append. 272 * @return Returns the index where this value was appended. If the value already exists in the array, 273 * returns the index in this array where the value was found. 274 */ 275 size_t appendUnique(const T& value) { 276 size_t ret; 277 if (find(value,ret) != DAE_OK) 278 return append(value); 279 else 280 return ret; 281 } 282 283 /** 284 * Adds a new item to the front of the @c daeArray. 285 * @param value Item to be added. 286 */ 287 void prepend(const T& value) { 288 insertAt(0, value); 289 } 290 291 /** 292 * Removes an item from the @c daeArray. 293 * @param value A reference to the item to delete. 294 * @return Returns DAE_OK if success, a negative value defined in daeError.h otherwise. 295 * @note The @c daeElement objects sometimes list 296 * objects in two places, the class member and the <i> @c _contents </i> array, when you remove something from the 297 * do, you must remove it from both places. 298 */ 299 daeInt remove(const T& value, size_t *idx = NULL ) 300 { 301 size_t index; 302 if(find(value,index) == DAE_OK) 303 { 304 if ( idx != NULL ) { 305 *idx = index; 306 } 307 return(removeIndex( index )); 308 } 309 else 310 { 311 return(DAE_ERR_INVALID_CALL); 312 } 313 } 314 /** 315 * Finds an item from the @c daeArray. 316 * @param value A reference to the item to find. 317 * @param index If the function returns DAE_OK, this is set to the index where the value appears in the array. 318 * @return Returns DAE_OK if no error or DAE_ERR_QUERY_NO_MATCH if the value was not found. 319 */ 320 daeInt find(const T& value, size_t &index) const 321 { 322 size_t i; 323 for(i=0;i<_count;i++) 324 { 325 if (((T*)_data)[i] == value) 326 { 327 index = i; 328 return DAE_OK; 329 } 330 } 331 332 return DAE_ERR_QUERY_NO_MATCH; 333 } 334 /** 335 * Just like the previous function, but has a more reasonable interface. 336 * @param value The value to find. 337 * @return Returns a pointer to the value if found, null otherwise. 338 */ 339 T* find(const T& value) const { 340 size_t i; 341 if (find(value, i) == DAE_OK) 342 return get(i); 343 return NULL; 344 } 345 /** 346 * Gets the object at a specific index in the @c daeArray. 347 * @param index Index of the object to get, asserts if the index is out of bounds. 348 * @return Returns the object at @c index. 349 */ 350 T& operator[](size_t index) { 351 assert(index < _count); 352 return ((T*)_data)[index]; } 353 /** 354 * Gets the object at a specific index in the @c daeArray. 355 * @param index Index of the object to get, asserts if the index is out of bounds. 356 * @return Returns the object at @c index. 357 */ 358 const T& operator[](size_t index) const { 359 assert(index < _count); 360 return ((T*)_data)[index]; } 361 362 /** 363 * Inserts the specified number of elements at a specific location in the array. 364 * @param index Index into the array where the elements will be inserted 365 * @param n The number of elements to insert 366 * @param val The value to insert 367 */ 368 void insert(size_t index, size_t n, const T& val = T()) { 369 if (index >= _count) { 370 // Append to the end of the array 371 size_t oldCount = _count; 372 setCount(index + n); 373 for (size_t i = oldCount; i < _count; i++) 374 get(i) = val; 375 } 376 else { 377 setCount(_count + n); 378 for (size_t i = _count-1; i >= index+n; i--) 379 get(i) = get(i-n); 380 for (size_t i = index; i < index+n; i++) 381 get(i) = val; 382 } 383 } 384 385 /** 386 * Inserts an object at a specific index in the daeArray, growing the array if neccessary 387 * @param index Index into the array for where to place the object 388 * @param value The object to append 389 */ 390 void insertAt(size_t index, const T& value) { 391 insert(index, 1); 392 get(index) = value; 393 } 394 395 /** 396 * Overloaded assignment operator. 397 * @param other A reference to the array to copy 398 * @return A reference to this object. 399 */ 400 daeTArray<T> &operator=( const daeTArray<T> &other ) { 401 if (this != &other) { 402 clear(); 403 _elementSize = other._elementSize; 404 _type = other._type; 405 grow(other._count); 406 for(size_t i=0;i<other._count;i++) 407 append(other[i]); 408 } 409 410 return *this; 411 } 412 413 /** 414 * Overloaded equality operator 415 * @param other A reference to the other array. 416 * @return true if the arrays are equal, false otherwise. 417 */ 418 bool operator==(const daeTArray<T>& other) { 419 if (getCount() != other.getCount()) 420 return false; 421 for (size_t i = 0; i < getCount(); i++) 422 if (get(i) != other.get(i)) 423 return false; 424 return true; 425 } 426 427 //some helpers 428 /** 429 * Sets the array to the contain the two values specified. 430 * @param one The first value. 431 * @param two The second value. 432 */ 433 void set2( const T &one, const T &two ) 434 { 435 setCount( 2 ); 436 set( 0, one ); 437 set( 1, two ); 438 } 439 /** 440 * Sets the array to the contain the three values specified. 441 * @param one The first value. 442 * @param two The second value. 443 * @param three The third value. 444 */ 445 void set3( const T &one, const T &two, const T &three ) 446 { 447 setCount( 3 ); 448 set( 0, one ); 449 set( 1, two ); 450 set( 2, three ); 451 } 452 /** 453 * Sets the array to the contain the four values specified. 454 * @param one The first value. 455 * @param two The second value. 456 * @param three The third value. 457 * @param four The fourth value. 458 */ 459 void set4( const T &one, const T &two, const T &three, const T &four ) 460 { 461 setCount( 4 ); 462 set( 0, one ); 463 set( 1, two ); 464 set( 2, three ); 465 set( 3, four ); 466 } 467 468 /** 469 * Sets the values in the array at the specified location to the contain the two 470 * values specified. This function will grow the array if needed. 471 * @param index The position in the array to start setting. 472 * @param one The first value. 473 * @param two The second value. 474 */ 475 void set2at( size_t index, const T &one, const T &two ) 476 { 477 set( index, one ); 478 set( index+1, two ); 479 } 480 /** 481 * Sets the values in the array at the specified location to the contain the three 482 * values specified. This function will grow the array if needed. 483 * @param index The position in the array to start setting. 484 * @param one The first value. 485 * @param two The second value. 486 * @param three The third value. 487 */ 488 void set3at( size_t index, const T &one, const T &two, const T &three ) 489 { 490 set( index, one ); 491 set( index+1, two ); 492 set( index+2, three ); 493 } 494 /** 495 * Sets the values in the array at the specified location to the contain the four 496 * values specified. This function will grow the array if needed. 497 * @param index The position in the array to start setting. 498 * @param one The first value. 499 * @param two The second value. 500 * @param three The third value. 501 * @param four The fourth value. 502 */ 503 void set4at( size_t index, const T &one, const T &two, const T &three, const T &four ) 504 { 505 set( index, one ); 506 set( index+1, two ); 507 set( index+2, three ); 508 set( index+3, four ); 509 } 510 511 /** 512 * Appends two values to the array. 513 * @param one The first value. 514 * @param two The second value. 515 */ 516 void append2( const T &one, const T &two ) 517 { 518 append( one ); 519 append( two ); 520 } 521 /** 522 * Appends three values to the array. 523 * @param one The first value. 524 * @param two The second value. 525 * @param three The third value. 526 */ 527 void append3( const T &one, const T &two, const T &three ) 528 { 529 append( one ); 530 append( two ); 531 append( three ); 532 } 533 /** 534 * Appends four values to the array. 535 * @param one The first value. 536 * @param two The second value. 537 * @param three The third value. 538 * @param four The fourth value. 539 */ 540 void append4( const T &one, const T &two, const T &three, const T &four ) 541 { 542 append( one ); 543 append( two ); 544 append( three ); 545 append( four ); 546 } 547 548 /** 549 * Inserts two values into the array at the specified location. 550 * @param index The position in the array to start inserting. 551 * @param one The first value. 552 * @param two The second value. 553 */ 554 void insert2at( size_t index, const T &one, const T &two ) 555 { 556 insert(index, 2); 557 set(index, one); 558 set(index+1, two); 559 } 560 /** 561 * Inserts three values into the array at the specified location. 562 * @param index The position in the array to start inserting. 563 * @param one The first value. 564 * @param two The second value. 565 * @param three The third value. 566 */ 567 void insert3at( size_t index, const T &one, const T &two, const T &three ) 568 { 569 insert(index, 3); 570 set( index, one ); 571 set( index+1, two ); 572 set( index+2, three ); 573 } 574 /** 575 * Inserts four values into the array at the specified location. 576 * @param index The position in the array to start inserting. 577 * @param one The first value. 578 * @param two The second value. 579 * @param three The third value. 580 * @param four The fourth value. 581 */ 582 void insert4at( size_t index, const T &one, const T &two, const T &three, const T &four ) 583 { 584 insert(index, 4); 585 set( index, one ); 586 set( index+1, two ); 587 set( index+2, three ); 588 set( index+4, four ); 589 } 590 591 /** 592 * Gets two values from the array at the specified location. 593 * @param index The position in the array to start getting. 594 * @param one Variable to store the first value. 595 * @param two Variable to store the second value. 596 * @return Returns The number of elements retrieved. 597 */ 598 daeInt get2at( size_t index, T &one, T &two ) 599 { 600 daeInt retVal = 0; 601 if ( index < _count ) 602 { 603 one = get(index); 604 retVal++; 605 } 606 if ( index+1 < _count ) 607 { 608 two = get(index+1); 609 retVal++; 610 } 611 return retVal; 612 } 613 /** 614 * Gets three values from the array at the specified location. 615 * @param index The position in the array to start getting. 616 * @param one Variable to store the first value. 617 * @param two Variable to store the second value. 618 * @param three Variable to store the third value. 619 * @return Returns The number of elements retrieved. 620 */ 621 daeInt get3at( size_t index, T &one, T &two, T &three ) 622 { 623 daeInt retVal = 0; 624 if ( index < _count ) 625 { 626 one = get(index); 627 retVal++; 628 } 629 if ( index+1 < _count ) 630 { 631 two = get(index+1); 632 retVal++; 633 } 634 if ( index+2 < _count ) 635 { 636 three = get(index+2); 637 retVal++; 638 } 639 return retVal; 640 } 641 /** 642 * Gets four values from the array at the specified location. 643 * @param index The position in the array to start getting. 644 * @param one Variable to store the first value. 645 * @param two Variable to store the second value. 646 * @param three Variable to store the third value. 647 * @param four Variable to store the fourth value. 648 * @return Returns The number of elements retrieved. 649 */ 650 daeInt get4at( size_t index, T &one, T &two, T &three, T &four ) 651 { 652 daeInt retVal = 0; 653 if ( index < _count ) 654 { 655 one = get(index); 656 retVal++; 657 } 658 if ( index+1 < _count ) 659 { 660 two = get(index+1); 661 retVal++; 662 } 663 if ( index+2 < _count ) 664 { 665 three = get(index+2); 666 retVal++; 667 } 668 if ( index+3 < _count ) 669 { 670 four = get(index+3); 671 retVal++; 672 } 673 return retVal; 674 } 675 676 /** 677 * Appends a number of elements to this array from a C native array. 678 * @param num The number of elements to append. 679 * @param array The C native array that contains the values to append. 680 */ 681 void appendArray( size_t num, T *array ) 682 { 683 if ( array == NULL ) 684 return; 685 686 for ( size_t i = 0; i < num; i++ ) 687 append( array[i] ); 688 } 689 /** 690 * Appends a number of elements to this array from another daeTArray. 691 * @param array The daeTArray that contains the values to append. 692 */ 693 void appendArray( const daeTArray<T> &array ){ 694 size_t num = array.getCount(); 695 for ( size_t i = 0; i < num; i++ ) 696 append( array[i] ); 697 } 698 }; 699 700 701 #endif //__DAE_ARRAY_H__ 702