# TableType reference

The TableType describes the type of a table, defined in

    type/TableType.h

. It inherits being an Mtarget from the Type, and can be shared between the threads after it has been initialized. However like RowType, it can benefit from creating a separate copy for each thread, to keep the reference count changes local to one CPU (see the method

    deepCopy()

below).

In the &Cpp; API it's built very similarly to the current Perl API, by constructing a bare object, then adding information to it, and finally initializing it. The Perl API will eventually change to something more Perl-like, the &Cpp; API will stay this way.

The creation goes like this:

    Autoref tt = initializeOrThrow( (new TableType(rt1))
    	->addSubIndex("primary", it
    	)->addSubIndex("secondary", itcopy
    	)
    );

In reality the index types would also be constructed as a part of this long statement but for clarity they were assumed to be pre-created as

    it

and

    itcopy

.

After a table type has been initialized, nothing can be added to it any more. Just as in the Perl API, the

    addSubIndex()

adds not its argument index type object but its deep copy (see more about the copy varieties in &xrsp;). When the table type gets initialized, these index types get tied to it.

Note that the operator

    new

has to be in parenthesis to get the priorities right. It's kind of annoying, so the better-looking equivalent way to do it is to use the static method

    make()

:

    Autoref tt = initializeOrThrow(TableType::make(rt1)
    	->addSubIndex("primary", it
    	)->addSubIndex("secondary", itcopy
    	)
    );

And here is a more complete example, with making of all the components in one chain:

    Autoref tt = initializeOrThrow(TableType::make(rt1)
    	->addSubIndex("primary", HashedIndexType::make(
    		NameSet::make()->add("a")->add("e"))
    		->setAggregator(new MyAggregatorType("onPrimary", NULL))
    		->addSubIndex("level2", new FifoIndexType)
    	)
    );

The construction-related methods are:

    TableType(Onceref rt);
    static TableType *make(Onceref rt);
    TableType *addSubIndex(const string &name, IndexType *index);
    void initialize();

The method

    initialize()

is called by the

    initializeOrThrow()

template, which then checks for errors and throws an Exception if it finds any. But you can call it manually instead if you wish.

The working of the

    addSubIndex()

is such that it doesn't put its

    this

object into any kind of Autoref. Because of that it's able to pass that pointer right through to its result for chaining. It doesn't check anything and can't throw any exceptions. So the TableType object created by the constructor gets through the chain of

    addSubIndex()

without having any counted references to it created, its reference count stays at 0. Only when the result of the chain is assigned to an Autoref, the first reference gets created. Obviously, this chain must not be interrupted by any exceptions or the memory will leak. Any detected errors must be collected in the embedded error objects, that will be read after initialization.

The result of initialization is void for a good reason: if you call

    initialize()

manually, you can't include it into this chain, and the void result forces the non-chained call. Before the initialization is called, the TableType object must be properly held in a counted reference. For example:

    Autoref tt = TableType::make(rt1)
    	->addSubIndex("primary", it
    	)->addSubIndex("secondary", itcopy
    	);
    tt->initialize();
    if (tt->getErrors()->hasError())
    	throw Exception(tt->getErrors());

But

    initializeOrThrow()

is smart enough to do things correctly within the chained call format. It saves the TableType in an Autoref, then calls

    initialize()

, and on success returns that Autoref, never corrupting the references. It involves a little more overhead but the TableType construction usually happens only once at the start-up time, and thus a minor difference in efficiency doesn't matter.

It's safe to call

    initialize()

multiple times, the repeated calls will simply have no effect.

The sub-indexes may be added only while the table type is not initialized, afterwards it will throw an Exception.

The methods to examine the contents of the table type are:

    bool isInitialized() const;

Check whether the table type has been initialized.

    const RowType *rowType() const;

Returns the row type of the table type. Since the table type is not expected to be destroyed immediately, it's OK to return a plain pointer.

    IndexType *findSubIndex(const string &name) const;

Find the index by name. If the index is not found, returns the special value

    NO_INDEX_TYPE

. This looks only for the top-level indexes, to find the nested indexes, the similar calls have to be continued on the further levels. At the moment there is no ready method to resolve a whole index path in &Cpp;, however the same method in IndexType allows to do it by simple chaining:

    Autoref it = tt->findSubIndex("level1")->findSubIndex("level2");
    if (it == NO_INDEX_TYPE) {
    	// not found
    }

Even though

    NO_INDEX_TYPE

is a pointer to a static value, it's safe to store it in an AutoRef, because this object's reference count gets initialized to 1, and AutoRef would never free it. The downside of the chaining compared with the path-resolving method in Perl is that this chain doesn't tell you, which of the indexes in the path were not found.

    IndexType *findSubIndexById(IndexType::IndexId it) const;

Finds the first index type of a particular kind (or

    NO_INDEX_TYPE

if none were found, similarly to

    findSubIndex()

). The ids are like IndexType::IT_HASHED, IndexType::IT_FIFO, IndexType::IT_SORTED.

    IndexType *getFirstLeaf() const;

Finds the first leaf index type. This call does search through the whole depth of the index tree for the first leaf index type.

    const IndexTypeVec &getSubIndexes() const;

Returns the vector with all the top-level index type references. The vector is read-only, you must not change it.

    TableType *copy() const;

Copy the table type, including all its contents of IndexTypes and AggregatorTypes, because they get tied to no more than one TableType. However the RowTypes stay shared. The copied table type is always uninitialized and thus can be further extended by defining more indexes and aggregators.

In case if the table type collected errors, the errors aren't copied, and in general you should not copy such a table type. The errors will be detected again when you try to initialize the copy.

    TableType *deepCopy(HoldRowTypes *holder) const;

Copy the whole strucutre all the way down, up to and including the row types. This is used for exporting the TableTypes to the other threads through a Nexus. It keeps the reference counts localized to each thread, preventing the thrashing of them between CPUs as the references are created and destroyed.

The HoldRowTypes object is what takes care of sharing the underlying row types. To copy a bunch of objects with sharing, you create a HoldRowTypes, copy the bunch, destroy the HoldRowTypes, as described in more detail in &xrsp;.

The Perl API contains one more copy method,

    copyFundamental()

. It's not directly available in the &Cpp; API yet but the same task can be done manually.

Ultimately, the TableType is used to construct the tables. The factory method is:

    Onceref makeTable(Unit *unit, const string &name) const;

This creates a table with the given name in a given unit. If the table type is not initialized or the initialization returned an error, will return NULL.

Finally, there is a call that you don't need to use:

    RowHandleType *rhType() const;

Like everything else, the RowHandles have a type. But this type is very much internal, and it knows very little about the row handles. All it knows is how much memory to allocate when constructing a new RowHandle. The rest of the knowledge about the RowHandles is placed inside the Table. So, a Table (yes, a Table, not a TableType) acts among the other things as a type for its RowHandles.

TableType
initializeOrThrow
Exception
IndexType
AggregatorType
HoldRowTypes
Nexus
RowHandleType