# RowType reference

In the Perl API a row type is a collection of fields. Under the hood the things are more complicated. In the &Cpp; API Triceps allows for more flexibility, more ways to represent a row. The row type is represented by the abstract base class RowType that tells the logical structure of a row and by its concrete subclasses that define the concrete layout of data in a row. To create, read or manipulate a row, all you need to know is a reference to RowType. It would refer to a concrete row type object, and the concrete row operations are accessed by the virtual methods. But when you create a row type, you need to know the concrete row type subclass.

Currently the choice is easy: there is only one such concrete subclass CompactRowType. The compact means that the data is stored in the rows in a compact form, one field value after another, without alignment. Perhaps some day there will be an AlignedRowType, allowing to read the values more efficiently. Or perhaps some day there will be a ZippedRowType that would store the data in the compressed format.

Naturally, RowType is a Mtarget, since it inherits from Type, and CompactRowType inherits from it. They are defined in

    type/RowType.h

and

    type/CompactRowType.h

but for the include purposes it's more customary to simply include

    type/AllTypes.h

.

You would never use the RowType constructor directly, it's called from the subclasses. Even if you care only about the logical structure of a row but not representation, you still can't directly construct a RowType because it's an abstract class. But just construct any concrete subclass, say CompactRowType (since it's the only one available at the moment anyway), and then use its logical structure. Every subclass is expected to define a similar constructor:

    RowType(const FieldVec &fields);
    CompactRowType(const FieldVec &fields);

The FieldVec is the definition of fields in the row type. It's defined as simple as:

    typedef vector FieldVec;

An important side note is that the field is defined within the RowType, so it's really RowType::FieldVec and RowType::Field, and you need to refer to them in your code by this qualified name. So, to create a row type, you create a vector of field definitions first and then construct the row type from it. You can throw away or modify that vector afterwards.

As usual for Type, the constructor arguments might not be correct, and any errors will be remembered and returned with

    getErrors()

. Don't use a type with errors (other than to read the error messages from it, and to destroy it), it might cause your program to crash.

A Field consists of the basic information about it: the name, the type, and the array indication (remember, a Triceps field may contain an array). The array indication is either RowType::Field::AR_SCALAR for a scalar value or RowType::Field::AR_VARIABLE for a variable-sized array. The original plan was also to use the integer values for the fixed-sized array fields, but in reality the variable-sized array fields have turned out to be easier to implement and that was it. So don't use the integer values. Most probably they would work like the same variable-sized arrays but they haven't been tested, and something somewhere might crash. Use the symbolic enum AR_*.

The normal Field constructor provides all this information:

    Field(const string &name, Autoref t, int arsz = AR_SCALAR);

Or you can use the default constructor and later change the fields in the Field (or of course read them) as you please, they are all public:

    string name_;
    Autoref  type_;
    int arsz_;

Or you can assign them later in one fell swoop:

    void assign(const string &name, Autoref t, int arsz = AR_SCALAR);

Note that even though theoretically you can define a field of any Type, in practice it has to be of a SimpleType, or the RowType constructor will return an error later. Why isn't it defined as an

    Autoref

then? The grand plan for the future is to allow some more interesting data structures in the rows, and this keeps the door open. In particular, the rows will be able to hold references to the other rows, just I haven't got to implementing it yet.

Once again, a RowType constructor makes a copy of the FieldVec for its use, so you can modify or destroy the original FieldVec right away. You can get back the information about the fields in RowType:

    const vector &fields() const;

It returns a reference directly to the FieldVec contained in the row type, so you must never modify it! The const-ness gives a reminder about it.

There are more row type constructors (but no default one). First, each subclass variety is supposed to be able to construct its variety by copying the logical structure of any RowType:

    CompactRowType(const RowType &proto);
    CompactRowType(const RowType *proto);

The version with the pointer argument also works for passing an

    Autoref

as the argument which gets automatically converted to a pointer (but be careful to not destroy the last reference until after the constructor returns). And it's really the more typically used one than the &-reference version.

The resulting type will have the same logical structure but possibly a different concrete representation than the original.

The second constructor variety is a factory method:

    virtual RowType *newSameFormat(const FieldVec &fields) const;

It combines the representation format from one row type and the arbitrary logical structure (the fields vector) from possibly another row type. Or course, until more of the concrete type representations become available, its use is largely theoretical.

And there is also a factory method that copies the current row type together with its concrete representation (it's really a convenience wrapper over

    newSameFormat()

):

    RowType *copy() const;

Let's get to some examples of constructing the row types. To reiterate, you don't construct the objects of RowType class itself, it's an abstract class. You construct the objects of the concrete subclass(es), specifically CompactRowType. Make a vector describing the fields and do the construction.

You can make the vector by either starting with an empty one and adding the fields to it or allocating a vector of the right size in advance and setting the fields in it:

    RowType::FieldVec fields1;
    fields1.push_back(RowType::Field("a", Type::r_int64)); // scalar by default
    fields1.push_back(RowType::Field("b", Type::r_int32, RowType::Field::AR_SCALAR));
    fields1.push_back(RowType::Field("c", Type::r_uint8, RowType::Field::AR_VARIABLE));

    RowType::FieldVec fields2(2);
    fields2[0].assign("a", Type::r_int64); // scalar by default
    fields2[1].assign("b", Type::r_int32, RowType::Field::AR_VARIABLE);

You can also reuse the same vector and clean/resize is as needed to create more types.

If you're used to laying out the C structures placing the larger elements first for the more efficient alignment, know that this is not needed for the Triceps rows. The CompactRowType stores the row data unaligned, so any field order will result in the same size of the rows. And it can't make use of some fields happening to be aligned either.

You can also find the simple types by their string names:

    fields1.push_back(RowType::Field("d", Type::findSimpleType("uint8"), RowType::Field::AR_VARIABLE));

If the type name is incorrect and the type is not found,

    findSimpleType()

will return NULL, which NULL will be caught later at the row type creation times. Note that there is no automatic look-up of the array types. You can't simply pass uint8[] to

    findSimpleType()

. You have to break it up into the simple type name as such an the array indication, like is done in

    perl/Triceps/RowType.xs

. This would probably a good thing to add to RowType::Field in the future.

You can't use the type Type::r_void for the fields, it will be reported as an error.

After the fields array is created, create the row type:

    Autoref rt1 = new CompactRowType(fields1);
    if (rt1->getErrors()->hasError())
    	throw Exception(rt1->getErrors(), true);

Or using the inialization templates:

    Autoref rt1 = checkOrThrow(new CompactRowType(fields1));

You could also use

    Autoref

but there isn't any point to it, since all the methods of CompactRowType are virtuals inherited from RowType.

Don't forget to check that the constructed type has no errors, and bail out if so. Throwing an Exception is a convenient way to abort with a nice error message, and the template

    checkOrThrow()

takes care of wrapping all the details.

The RowType and its subclasses are immutable after construction, so they can be shared between threads all you want. Depending on your approach to the threads, it might be more efficient to create a separate copy of the row type for each thread. This way when the references to the row types are created and deleted, the reference count can stay in the cache of one CPU and thus be more efficient. The thread support of the Triceps library does use this approach and creates the copies whenever the row types are imported from a nexus.

There are multiple equivalent ways to create a copy:

    Autoref rt2 = rt1->copy();
    Autoref rt3 = rt1->newSameFormat(rt1->fields());
    Autoref rt4 = new CompactRowType(rt1);

Checking the errors after the copy creation is optional if the original type was correct.

If you want to extend a type with more fields, make a copy of its fields and extend it:

    RowType::FieldVec fields3 = rt1->fields();
    fields3.push_back(RowType::Field("z", Type::r_string));
    Autoref rt3 = checkOrThrow(new CompactRowType(fields3));

That's about it for the RowType construction.

The information about the contents of a RowType can be read back:

    int fieldCount() const;
    const vector &fields() const;
    int findIdx(const string &fname) const;
    const Field *find(const string &fname) const;

    fields()

had already been described.

    fieldCount()

returns the count of fields.

    findIdx()

finds the index of the field by name, so that it can then be looked up in the result of

    fields()

. Or -1 if there is no such field.

    find()

directly returns the pointer to the field by name, combining these two actions. (Or it returns NULL if there is no such field).

The rest of the RowType methods have to do with the manipulation of the rows. They are described in &xrsp;.

RowType
CompactRowType
FieldVec
Field
SimpleType
Type