3ds Max C++ API Reference
Tab< T > Class Template Reference

Generic container class. More...

#include <tab.h>

+ Inheritance diagram for Tab< T >:

Public Member Functions

 Tab ()
 Default constructor. More...
 
 Tab (const Tab &tb)
 Copy constructor. More...
 
virtual ~Tab ()
 Destructor. More...
 
void Init ()
 Initializes a Tab instance. More...
 
int Count () const
 Retrieves the number of items in the Tab. More...
 
constexpr size_t size () const noexcept
 Retrieves the number of items in the Tab. Standard compliant. More...
 
void ZeroCount ()
 Resets the number of used items to zero. More...
 
void SetCount (int n, BOOL resize=TRUE)
 Sets the number of used items. More...
 
T * Addr (const INT_PTR i) const
 Returns the address of the i-th item. More...
 
constexpr T * data () noexcept
 Returns a pointer to the data buffer of tab. Standard compliant. More...
 
constexpr const T * data () const noexcept
 Returns a const pointer to the data buffer of tab. Standard compliant. More...
 
int Insert (int at, int num, T *el)
 Inserts items in the Tab at a specified position. More...
 
int Append (int num, T *el, int allocExtra=0)
 Appends items at the end of the Tab. More...
 
int Delete (int start, int num)
 Deletes items from the Tab. More...
 
int Resize (int num)
 Changes the number of items allocated in memory. More...
 
void Shrink ()
 Frees unused Tab items to reduce memory footprint. More...
 
void Sort (CompareFnc cmp)
 Sorts the array using the compare function. More...
 
Taboperator= (const Tab &tb)
 Assignment operator. More...
 
T & operator[] (const INT_PTR i) const
 Accesses the i-th Tab item. More...
 
const T * begin () const
 Accesses the begin iterator, which is a plain pointer in this case. More...
 
T * begin ()
 
const T * end () const
 Accesses the end iterator (one past last valid element). Do not dereference. More...
 
T * end ()
 

Additional Inherited Members

- Static Public Member Functions inherited from MaxHeapOperators
static UtilExport voidoperator new (size_t size)
 Standard new operator used to allocate objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e)
 Standard new operator used to allocate objects if there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate objects that takes the type of memory, filename and line number where the new was called If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate objects that takes the filename and line number where the new was called If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new (size_t size, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate objects that takes extra flags to specify special operations If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, int block_type, const char *filename, int line)
 New operator used to allocate arrays of objects. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, const char *filename, int line)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport voidoperator new[] (size_t size, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, an exception will be thrown. More...
 
static UtilExport voidoperator new[] (size_t size, const std::nothrow_t &e, unsigned long flags)
 New operator used to allocate arrays of objects If there is insufficient memory, NULL will be returned. More...
 
static UtilExport void operator delete (void *ptr)
 Standard delete operator used to deallocate an object If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an object If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an object that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an object that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete (void *ptr, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an object that takes extra flags to specify special operations If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e)
 Standard delete operator used to deallocate an array of objects If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, int block_type, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the type of memory, filename and line number where the delete was called If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, const char *filename, int line)
 Delete operator used to deallocate an array of objects that takes the filename and line number where the delete was called If the pointer is invalid, nothing will happen. More...
 
static UtilExport void operator delete[] (void *ptr, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport void operator delete[] (void *ptr, const std::nothrow_t &e, unsigned long flags)
 Delete operator used to deallocate an array of objects that takes extra flags to specify special operations If the pointer is invalid, an exception will be thrown. More...
 
static UtilExport voidoperator new (size_t size, void *placement_ptr)
 Placement new operator. More...
 
static UtilExport void operator delete (void *ptr, void *placement_ptr)
 Placement delete operator. More...
 
static UtilExport voidaligned_malloc (size_t size, size_t alignment)
 Allocates memory on a specified alignment boundary. More...
 
static UtilExport voidaligned_realloc (void *ptr, size_t size, size_t alignment)
 Reallocates memory on a specified alignment boundary. More...
 
static UtilExport void aligned_free (void *ptr)
 Frees a block of memory that was allocated with aligned_malloc/aligned_realloc. More...
 

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 MSTRs 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

Constructor & Destructor Documentation

◆ Tab() [1/2]

Tab ( )
inline

Default constructor.

186  : th(NULL)
187  {
189  }
#define ADSK_MAXSDK_IS_PLAIN_OLD_DATA_TYPE(_Typename)
Definition: PodTypeCheck.h:142
#define NULL
Definition: autoptr.h:18

◆ Tab() [2/2]

Tab ( const Tab< T > &  tb)
inline

Copy constructor.

Parameters
[in]tbThe Tab that will be copied
194  : th(NULL)
195  {
197  TBCopy((TabHdr**)&th, tb.Count(), (tb.th ? &tb.th->data : NULL), sizeof(T));
198  }
int Count() const
Retrieves the number of items in the Tab.
Definition: tab.h:219
Definition: tab.h:53
UtilExport int TBCopy(TabHdr **pth, int num, const void *el, int elsize)

◆ ~Tab()

virtual ~Tab ( )
inlinevirtual

Destructor.

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

204  {
205  zfree((void**)&th);
206  }
UtilExport void zfree(void **p)

Member Function Documentation

◆ Init()

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).

212  {
213  th = nullptr;
214  }

◆ Count()

int Count ( ) const
inline

Retrieves the number of items in the Tab.

Returns
The number of items in use in the Tab
220  {
221  if (th) {
222  return (th->count);
223  }
224  return 0;
225  }

◆ size()

constexpr size_t size ( ) const
inlineconstexprnoexcept

Retrieves the number of items in the Tab. Standard compliant.

Returns
The number of items in the tab.
231  {
232  if (th == nullptr)
233  return 0;
234 
235  return size_t(th->count);
236  }
MAXMEM_EXTERN_C UtilExport size_t(__cdecl *MAX_msize)(void *memblock)

◆ ZeroCount()

void ZeroCount ( )
inline

Resets the number of used items to zero.

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

243  {
244  if (th) {
245  th->count = 0;
246  }
247  }

◆ SetCount()

void SetCount ( int  n,
BOOL  resize = TRUE 
)
inline

Sets the number of used items.

Parameters
nThe number of used items to set
resizeIf TRUE, the Tab is resized to n items
253  {
254  TBSetCount((TabHdr **)&th, n, sizeof(T), resize);
255  }
UtilExport void TBSetCount(TabHdr **pth, int n, int elsize, BOOL resize)

◆ Addr()

T* Addr ( const INT_PTR  i) const
inline

Returns the address of the i-th item.

Parameters
iThe index of the item whose address is to be returned. If the index is out of bounds it will throw a MaxSDK::Util::TabOutOfRangeException exception.
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.
264  {
265  DbgAssert(th);
266  DbgAssert(i >= 0);
267  DbgAssert(th && i < th->count);
268  if (!th || i < 0 || (i >= th->count))
269  {
270  throw MaxSDK::Util::TabOutOfRangeException(_M("Invalid index passed into a Max SDK Tab::Addr(const INT_PTR i)"));
271  }
272  return (&th->data[i]);
273  }
Thrown when an invalid index is passed into Tab::operator[] or Tab::Addr.
Definition: tab.h:92
#define DbgAssert(expr)
Definition: assert1.h:82
#define _M(x)
Used to wrap string literals.
Definition: strbasic.h:67

◆ data() [1/2]

constexpr T* data ( )
inlineconstexprnoexcept

Returns a pointer to the data buffer of tab. Standard compliant.

Returns
A pointer to the tab data buffer.
279  {
280  if (th == nullptr)
281  return nullptr;
282 
283  return th->data;
284  }

◆ data() [2/2]

constexpr const T* data ( ) const
inlineconstexprnoexcept

Returns a const pointer to the data buffer of tab. Standard compliant.

Returns
A const pointer to the tab data buffer.
289  {
290  if (th == nullptr)
291  return nullptr;
292 
293  return th->data;
294  }

◆ Insert()

int Insert ( int  at,
int  num,
T *  el 
)
inline

Inserts items in the Tab at a specified position.

Parameters
atIndex where to insert the items.
numNumber of items to insert
elPointer to the start of an array of items to insert
Returns
If the insertion was successful, returns the value of at.
302  {
303  return (TBInsertAt((TabHdr**)&th, at, num, (void *)el, sizeof(T), 0));
304  }
UtilExport int TBInsertAt(TabHdr **pth, int at, int num, const void *el, int elsize, int extra)

◆ Append()

int Append ( int  num,
T *  el,
int  allocExtra = 0 
)
inline

Appends items at the end of the Tab.

Parameters
numNumber of items to append
elPointer to the start of an array of items to insert
allocExtraNumber 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
313  {
314  return (TBInsertAt((TabHdr**)&th, (th ? th->count : 0), num, (void *)el, sizeof(T), allocExtra));
315  }
CNT count
Definition: tab.h:54

◆ Delete()

int Delete ( int  start,
int  num 
)
inline

Deletes items from the Tab.

Parameters
startThe index of the item the deletion starts at
numThe number of items to be deleted
Returns
The number of items left in the table
322  {
323  return (TBDelete((TabHdr**)&th, start, num, sizeof(T)));
324  }
UtilExport int TBDelete(TabHdr **pth, int starting, int num, int elsize)

◆ Resize()

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
numThe new size (in number of items) of the array
Returns
Nonzero if the array was resized; otherwise 0.
336  {
337  return (TBMakeSize((TabHdr**)&th, num, sizeof(T)));
338  }
UtilExport int TBMakeSize(TabHdr **pth, int num, int elsize)

◆ Shrink()

void Shrink ( )
inline

Frees unused Tab items to reduce memory footprint.

341  {
342  TBMakeSize((TabHdr**)&th, (th ? th->count : 0), sizeof(T));
343  }

◆ Sort()

void Sort ( CompareFnc  cmp)
inline

Sorts the array using the compare function.

Parameters
cmpPointer 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);
MAXMEM_EXTERN_C UtilExport int(__cdecl *MAX_heapchk)(void)
int(__cdecl * CompareFnc)(const void *elem1, const void *elem2)
Definition: tab.h:113
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) {
const MCHAR* a = (const MCHAR*)item1;
const MCHAR* b = (const MCHAR*)item2;
return(_tcscmp(a, b));
}
#define MCHAR
MBCS/Unicode helper defines std::wofstream doesn't mix well with Unicode.
Definition: strbasic.h:42
366  {
367  if (th) {
368  qsort(th->data, th->count, sizeof(T), cmp);
369  }
370  }

◆ operator=()

Tab& operator= ( const Tab< T > &  tb)
inline

Assignment operator.

Parameters
tbThe 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
378  {
379  TBCopy((TabHdr**)&th, tb.Count(), (tb.th ? &tb.th->data : NULL), sizeof(T));
380  return *this;
381  }

◆ operator[]()

T& operator[] ( const INT_PTR  i) const
inline

Accesses the i-th Tab item.

Parameters
iThe index of the Tab item to access. If the index is out of bounds it will throw a MaxSDK::Util::TabOutOfRangeException exception. The index is bounds checked.
Returns
Reference to the object in the i-th item.
389  {
390  DbgAssert(th);
391  DbgAssert(i >= 0);
392  DbgAssert(th && i < th->count);
393  if (!th || i < 0 || (i >= th->count))
394  {
395  throw MaxSDK::Util::TabOutOfRangeException(_M("Invalid index passed into a Max SDK Tab::operator[]"));
396  }
397 
398  return (th->data[i]);
399  }

◆ begin() [1/2]

const T* begin ( ) const
inline

Accesses the begin iterator, which is a plain pointer in this case.

402  {
403  if (th == nullptr)
404  return nullptr;
405 
406  return th->data;
407  }

◆ begin() [2/2]

T* begin ( )
inline
408  {
409  if (th == nullptr)
410  return nullptr;
411 
412  return th->data;
413  }

◆ end() [1/2]

const T* end ( ) const
inline

Accesses the end iterator (one past last valid element). Do not dereference.

416  {
417  if (th == nullptr)
418  return nullptr;
419 
420  return th->data + th->count;
421  }

◆ end() [2/2]

T* end ( )
inline
422  {
423  if (th == nullptr)
424  return nullptr;
425 
426  return th->data + th->count;
427  }