Public Member Functions

Tab< T > Class Template Reference

This reference page is linked to from the following overview topics: General Best Practices, Parameter Specification Arguments, Parameter Types, Parameter Flags, Parameter UI Control Types, List Box Control Types, Responding to Node Deletion, Containers, Computing Vertex Normals, Retrieving Mesh Strip Data, Mesh Example, Core Interfaces, Property Accessors, Symbolic Enumerations, Parameter/Result Types, Supported Types, Using FPInterface::Invoke(), Collections.


Search for all occurrences

Detailed Description

template<class T>
class Tab< T >

Generic container class.

This is a type-safe variable length array class which also supports list-like operations of insertion, appending and deleting. Two instance variables are maintained: nalloc is the number items allocated in the array; count is the number actual used (count<=nalloc). Allocation is performed automatically when Insert or Append operations are performed. It can also be done manually by calling Resize() or Shrink().

Note:
Delete does not resize the storage: to do this call Shrink(). If you are going to do a sequence of Appends, its more efficient to first call Resize() to make room for them. Beware of using the Addr() function: it returns a pointer which may be invalid after subsequent Insert(), Append(), Delete(), Resize(), or Shrink() operations.
In 3ds max 1.x, the method SetCount(n) will set the count to n, but will not assure that only n items are allocated. To do that you should call Resize(n). This sets the number allocated. It will also make sure that count<=numAlloc. To make sure that exactly n are allocated and that count = n, call both Resize(n) and SetCount(n). In 3ds max 2.x and later using SetCount() will also effectively call Resize().
This structure is not meant to support more than 2G items; if you need to have more items, consider using an STL container which does not have the 2G barrier and is most likely more optimized than this version.

The implementation minimizes the storage of empty Tables: they are represented by a single NULL pointer. Also, the major part of the code is generic, shared by different Tabs for different types of items.

Tabs may be used on the stack, i.e. they may be declared as a local variable of a function or method. You can set the number of items in the table, work with them, and then when the function returns, the destructor of the Tab is called, and the memory will be deallocated.

Tabs are only appropriate for use with classes that don't allocate memory. For example, Tab<float> is fine while Tab<MSTR> is problematic (MSTR is the class used for strings in 3ds max). In this case, the MSTR class itself allocates memory for the string. It relies on its constructor or destructor to allocate and free the memory. The problem is the Tab class will not call the constructors and destructors for all the items in the table, nor will it call the copy operator. As an example of this, when you assign a string to another string, the MSTR class does not just copy the pointer to the string buffer (which would result in two items pointing to the same block of memory). Rather it will allocate new memory and copy the contents of the source buffer. In this way you have two individual pointers pointing at two individual buffers. When each of the MSTR destructors is called it will free each piece of memory. So, the problem with using a Tab<MSTR> is that when you assign a Tab to another Tab, the Tab copy constructor will copy all the items in the table, but it will not call the copy operator on the individual items. Thus, if you had a Tab<MSTR> and you assigned it to another Tab<MSTR>, you'd have two TSTRs pointing to the same memory. Then when the second one gets deleted it will be trying to double free that memory.

So again, you should only put things in a Tab that don't allocate and deallocate memory in their destructors. Thus, this class should not be used with classes that implement an assignment operator and or destructor because neither are guaranteed to be called. The way around this is to use a table of pointers to the items. For example, instead of Tab<MSTR> use Tab <MSTR *>. As another example, Tab<int> is OK, while Tab<BitArray> would be no good. In the BitArray case one should use class pointers, i.e. Tab<BitArray *>.

All methods of this class are implemented by the system except the compare function used in sorting (see Sort()).

See also:
class BitArray, class MaxSDK::Array

#include <tab.h>

Inheritance diagram for Tab< T >:
Inheritance graph
[legend]

List of all members.

Public Member Functions

  Tab ()
  Default constructor.
  Tab (const Tab &tb)
  Copy constructor.
  ~Tab ()
  Destructor.
void  Init ()
  Initializes a Tab instance.
int  Count () const
  Retrieves the number of items in the Tab.
void  ZeroCount ()
  Resets the number of used items to zero.
void  SetCount (int n, BOOL resize=TRUE)
  Sets the number of used items.
T *  Addr (const INT_PTR i) const
  Returns the address of the i-th item.
int  Insert (int at, int num, T *el)
  Inserts items in the Tab at a specified position.
int  Append (int num, T *el, int allocExtra=0)
  Appends items at the end of the Tab.
int  Delete (int start, int num)
  Deletes items from the Tab.
int  Resize (int num)
  Changes the number of items allocated in memory.
void  Shrink ()
  Frees unused Tab items to reduce memory footprint.
void  Sort (CompareFnc cmp)
  Sorts the array using the compare function.
Tab operator= (const Tab &tb)
  Assignment operator.
T &  operator[] (const INT_PTR i) const
  Accesses the i-th Tab item.

Constructor & Destructor Documentation

Tab ( ) [inline]

Default constructor.

: th(0) { }
Tab ( const Tab< T > &  tb ) [inline]

Copy constructor.

Parameters:
[in] tb The Tab that will be copied
                           : th(0) {  
            TBCopy((TabHdr**)&th, 0, tb.Count(), (tb.th ? &tb.th->data : NULL), sizeof(T)); 
        }
~Tab ( ) [inline]

Destructor.

The memory occupied by the Tab's items is freed, but the objects pointed by the items are not.

               {
            zfree((void**)&th); 
        }

Member Function Documentation

void Init ( ) [inline]

Initializes a Tab instance.

Provides a way of initializing a Tab instance outside of its constructor, such as when they are are in-place constructed (constructed in pre-allocated memory).

                    {
            th = 0;
        }
int Count ( ) const [inline]

Retrieves the number of items in the Tab.

Returns:
The number of items in use in the Tab

Reimplemented in XMLAnimTreeEntryList.

        { 
            if (th) {
                return (th->count); 
            }
            return 0; 
        }  
void ZeroCount ( ) [inline]

Resets the number of used items to zero.

WARNING: Using this method does not free any of the allocated memory stored.

Reimplemented in NameTab, and XMLAnimTreeEntryList.

        { 
            if (th) {
                th->count = 0; 
            }
        }
void SetCount ( int  n,
BOOL  resize = TRUE 
) [inline]

Sets the number of used items.

Parameters:
n The number of used items to set
resize If TRUE, the Tab is resized to n items
                                               { 
            TBSetCount((TabHdr **)&th, n, sizeof(T), resize); 
        }
T* Addr ( const INT_PTR  i ) const [inline]

Returns the address of the i-th item.

Parameters:
i The index of the item whose address is to be returned
Returns:
Pointer to the i-th item
Note:
This method returns a pointer which may be invalid after subsequent Insert, Append, Delete, Resize, or Shrink operations.
                                       {             
            DbgAssert(th);
            DbgAssert(i < th->count); 
            return (&th->data[i]); 
        }
int Insert ( int  at,
int  num,
T *  el 
) [inline]

Inserts items in the Tab at a specified position.

Parameters:
at Index where to insert the items.
num Number of items to insert
el Pointer to the start of an array of items to insert
Returns:
If the insertion was successful, returns the value of at.
                                           {
            return (TBInsertAt((TabHdr**)&th, at, num, (void *)el, sizeof(T), 0));
        }
int Append ( int  num,
T *  el,
int  allocExtra = 0 
) [inline]

Appends items at the end of the Tab.

Parameters:
num Number of items to append
el Pointer to the start of an array of items to insert
allocExtra Number of extra Tab elements to be allocated in order to enlarge the Tab.
Returns:
Returns the number of items in use (count of items) prior to appending
                                                     {
            return (TBInsertAt((TabHdr**)&th, (th ? th->count : 0), num, (void *)el, sizeof(T), allocExtra)); 
        }
int Delete ( int  start,
int  num 
) [inline]

Deletes items from the Tab.

Parameters:
start The index of the item the deletion starts at
num The number of items to be deleted
Returns:
The number of items left in the table

Reimplemented in XMLAnimTreeEntryList.

                                       { 
            return (TBDelete((TabHdr**)&th, start, num, sizeof(T)));
        } 
int Resize ( int  num ) [inline]

Changes the number of items allocated in memory.

Resize sets the amount of allocated memory, but doesn't change the actual number of items said to be in the tab So if you know you will want a Tab with 1000 items, you could use Resize to pre-allocate the memory for the 1000 items, and then use Append to add each item without taking a hit on reallocs as the count increases

Parameters:
num The new size (in number of items) of the array
Returns:
Nonzero if the array was resized; otherwise 0.
                            { 
            return (TBMakeSize((TabHdr**)&th, num, sizeof(T)));
        }   
void Shrink ( ) [inline]

Frees unused Tab items to reduce memory footprint.

Reimplemented in XMLAnimTreeEntryList.

                      {
            TBMakeSize((TabHdr**)&th, (th ? th->count : 0), sizeof(T)); 
        }
void Sort ( CompareFnc  cmp ) [inline]

Sorts the array using the compare function.

Parameters:
cmp Pointer to the comparison function to the used by Sort to compare Tab items.
Note:
: Sort() uses the C library qsort function. 3rd party developers must implement the CompareFnc function.
        typedef int( __cdecl *CompareFnc) (const void *item1, const void *item2);
The return value of CompareFnc is show below: < 0 - if item1 less than item2 0 - if item 1 is identical to item2 > 0 - if item1 is greater than item2
        static int CompTable(const void* item1, const void* item2) {
            MCHAR* a = (MCHAR*)item1;
            MCHAR* b = (MCHAR*)item2;
            return(_tcscmp(a, b));
        }
        {
            if (th) {
                qsort(th->data, th->count, sizeof(T), cmp);
            }
        }
Tab& operator= ( const Tab< T > &  tb ) [inline]

Assignment operator.

Parameters:
tb The Tab to copy the items from
Note:
The objects pointed to by the Tab items are not copied, only the Tab items are copied.
Returns:
Reference to this Tab
                                      {
            TBCopy((TabHdr**)&th, 0, tb.Count(), (tb.th ? &tb.th->data : NULL), sizeof(T)); 
            return *this;
        }
T& operator[] ( const INT_PTR  i ) const [inline]

Accesses the i-th Tab item.

Parameters:
i The index of the Tab item to access
Returns:
Reference to the object in the i-th item.
                                             {       
            DbgAssert(th);
            DbgAssert(i < th->count); 
            return (th->data[i]); 
        }