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.
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().
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()).
#include <tab.h>
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.
|
Tab | ( | ) | [inline] |
Default constructor.
: th(0) { }
~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);
}
void Init | ( | ) | [inline] |
int Count | ( | ) | const [inline] |
Retrieves the number of items 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] |
T* Addr | ( | const INT_PTR | i | ) | const [inline] |
Returns the address of the i-th item.
i | The index of the item whose address is to be returned |
int Insert | ( | int | at, |
int | num, | ||
T * | el | ||
) | [inline] |
Inserts items in the Tab at a specified position.
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 |
{ return (TBInsertAt((TabHdr**)&th, at, num, (void *)el, sizeof(T), 0)); }
int Append | ( | int | num, |
T * | el, | ||
int | allocExtra =
0 |
||
) | [inline] |
int Delete | ( | int | start, |
int | num | ||
) | [inline] |
Deletes items from the Tab.
start | The index of the item the deletion starts at |
num | The number of items to be deleted |
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
num | The new size (in number of items) of the array |
{ return (TBMakeSize((TabHdr**)&th, num, sizeof(T))); }
void Shrink | ( | ) | [inline] |
Frees unused Tab items to reduce memory footprint.
Reimplemented in XMLAnimTreeEntryList.
void Sort | ( | CompareFnc | cmp | ) | [inline] |
Sorts the array using the compare function.
cmp | Pointer to the comparison function to the used by Sort to compare Tab items. |
typedef int( __cdecl *CompareFnc) (const void *item1, const void *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); } }