![]() |
VRS
A file format for sensor data.
|
The DataLayout class describes the data stored inside a DataLayoutContentBlock. More...
#include <DataLayout.h>
Classes | |
class | IndexEntry |
Describes where the data of a variable size DataPiece is in the varData_ buffer. More... | |
Public Member Functions | |
DataLayout & | operator= (const DataLayout &)=delete |
DataLayout (const DataLayout &)=delete | |
virtual | ~DataLayout () |
ContentBlock | getContentBlock () const |
vector< int8_t > & | getFixedData () |
vector< int8_t > & | getVarData () |
size_t | getFixedDataSizeNeeded () const |
size_t | getVarDataSizeFromIndex () const |
size_t | getVarDataSizeNeeded () const |
void | collectVariableDataAndUpdateIndex () |
void | collectVariableDataAndUpdateIndex (void *destination) |
void | getRawData (vector< int8_t > &outRawData) const |
void | stageCurrentValues () |
bool | copyClonedDataPieceValues (const DataLayout &originalLayout) |
bool | mapLayout (DataLayout &targetLayout) |
bool | isMapped () const |
bool | hasAllRequiredPieces () const |
void | requireAllPieces () |
Mark all the fields of the layout as required. | |
void | printLayout (ostream &out, const string &indent="") const |
void | printLayoutCompact (ostream &out, const string &indent="") const |
string | asJson (JsonFormatProfile profile) const |
string | asJson (const JsonFormatProfileSpec &profile=JsonFormatProfileSpec()) const |
string | getListOfPiecesSpec () const |
Get a text list of fields, types & names, one per line. Useful for tests. | |
bool | isSame (const DataLayout &otherLayout) const |
template<class T > | |
const DataPieceValue< T > * | findDataPieceValue (const string &label) const |
template<class T > | |
DataPieceValue< T > * | findDataPieceValue (const string &label) |
template<class T > | |
const DataPieceArray< T > * | findDataPieceArray (const string &label, size_t arraySize) const |
template<class T > | |
DataPieceArray< T > * | findDataPieceArray (const string &label, size_t arraySize) |
template<class T > | |
const DataPieceVector< T > * | findDataPieceVector (const string &label) const |
template<class T > | |
DataPieceVector< T > * | findDataPieceVector (const string &label) |
template<class T > | |
const DataPieceStringMap< T > * | findDataPieceStringMap (const string &label) const |
template<class T > | |
DataPieceStringMap< T > * | findDataPieceStringMap (const string &label) |
const DataPieceString * | findDataPieceString (const string &label) const |
DataPieceString * | findDataPieceString (const string &label) |
void | forEachDataPiece (const std::function< void(const DataPiece *)> &, DataPieceType type=DataPieceType::Undefined) const |
void | forEachDataPiece (const std::function< void(DataPiece *)> &, DataPieceType type=DataPieceType::Undefined) |
Same as above, but as a non-const version. | |
bool | isVarDataIndexValid () const |
size_t | getDeclaredFixedDataPiecesCount () const |
size_t | getDeclaredVarDataPiecesCount () const |
size_t | getAvailableFixedDataPiecesCount () const |
size_t | getAvailableVarDataPiecesCount () const |
Static Public Member Functions | |
static unique_ptr< DataLayout > | makeFromJson (const string &json) |
Static Public Attributes | |
static const size_t | kNotFound = numeric_limits<size_t>::max() |
Special OffsetAndLength offset value marking that a piece of data isn't available. | |
static const size_t | kVariableSize = numeric_limits<size_t>::max() - 1 |
Special value used for a DataPiece size, telling that that DataPiece has a variable size. | |
Protected Member Functions | |
template<class T > | |
T * | getFixedData (size_t offset, size_t size) |
const IndexEntry * | getVarSizeIndex () const |
IndexEntry * | getVarSizeIndex () |
template<class T > | |
T * | getVarData (size_t varPieceIndex, size_t &outCount) |
void | initLayout () |
void | serialize (JsonWrapper &rj, const JsonFormatProfileSpec &profile) const |
Static Protected Member Functions | |
static bool | mapPieces (const vector< DataPiece * > &searchPieces, const vector< DataPiece * > &givenPieces) |
Protected Attributes | |
vector< DataPiece * > | fixedSizePieces_ |
Ordered fixed-size DataPieces. | |
vector< DataPiece * > | varSizePieces_ |
Ordered variable-size DataPieces. | |
vector< int8_t > | fixedData_ |
Buffer to hold fixed-size pieces, and the index of var size pieces (if any). | |
size_t | fixedDataSizeNeeded_ {} |
Byte count for all the fixed size pieces + var size index. | |
vector< int8_t > | varData_ |
Buffer holding variable-size pieces, after they've been collected, or read from disk. | |
bool | hasAllRequiredPieces_ {true} |
Tells all the required pieces have been mapped successfully. | |
DataLayout * | mappedDataLayout_ {} |
DataLayout this layout has been mapped to, if any. | |
The DataLayout class describes the data stored inside a DataLayoutContentBlock.
A DataLayout object is usually constructed using AutoDataLayout and AutoDataLayoutEnd helpers. This method allows the easy & safe definition of a DataLayout in the form of a struct. The member variables of an AutoDataLayout allow the easy access of the individual pieces of content that make up a DataLayoutContentBlock, both for writing & reading.
Note that though DataLayout objects may look like structs, constructing them is relatively expensive, and creating AutoDataLayout objects involve a synchronisation lock. Therefore, avoid creating & destroying using short lived AutoDataLayout stack variables. Instead, prefer allocating the DataLayout objects you will need frequently as member variables of other classes that are long lived.
A DataLayout object can generate a json representation of itself, that is stored by VRS as an internal tag of a VRS record stream. This json data will be used when reading the VRS file to interpret the data of the corresponding DataLayoutContentBlock. The instantiation of a DataLayout from a json message is meant for exclusive use by VRS itself, when reading a file. VRS is very careful to only do this json expensive deserialization once per type.
The key feature of DataLayout is the separation of the layout description saved once per stream, from the actual payload in each record, which can be minimal, containing only binary data. The DataLayout sections of records are not stored in json format.
Most methods of this class are meant for exclusive use by VRS itself, even if they are public.
A DataLayout is an ordered collection of individual pieces of data, all deriving from the DataPiece abstract class. Classes deriving from DataPiece fall in two categories: Fixed-size DataPiece objects, and variable-size DataPiece objects.
Fixed-size DataPiece objects, use the same number of bytes, no matter the actual value:
DataLayout supports the following POD types:
DataPieceValue<T> and DataPieceArray<T> are the two fixed size DataPiece template classes.
Note: You can not use DataLayout template types with your own POD types, because:
Variable-size DataPiece objects use a number of bytes that depends on their actual value:
Internal representation (what you don't need to know unless you are working on DataLayout)
Because there is a known fixed number of fixed-size DataPiece objects, each of known size, we can pre-allocate a buffer to hold the data values of all those DataPiece objects. Fixed-size DataPiece objects reference their data using an offset and the size of their data. All read & write value operations on fixed-size DataPiece objects use that buffer, so that we can directly read from and write to disk that part of a DataLayout's data. That buffer is the first section of the fixedData_ byte vector.
For variable-size DataPiece objects, because the DataPiece data has an unforeseeable size, data reads & writes are not handled the same as for fixed-size DataPiece objects. Variable-size DataPiece objects don't have setter methods, but "stage" methods, that set the value in a field of the DataPiece object itself. The "stage" methods also allows to read the staged values. Once the value of all the variable-size DataPiece objects are staged, the staged values can be collected in a buffer, the varData_ byte vector. To interpret a variable size buffer read from disk, we need an index, to know where each piece starts, and their size. That's the variable size index. The size of that index is known ahead of time, since there is one index entry per variable-size DataPiece, and we know up-front how many we have. The index is stored in the fixedData_ vector, after the data of fixed-size DataPiece values. The values of the index are set when the variable size data is collected. When reading the value of a variable-size DataPiece, the varData_ buffer is used, if present.
To write a DataLayout section, the 3 following operations are needed:
Therefore, to read & write the data of a DataLayout from & to disk, there is no encoding of the data, unlike with json, which guaranties the bit accuracy of your data. That can be critically important when using float & double numbers.
Of course, all of this is the responsibility of VRS itself.
|
virtualdefault |
DataLayout has no virtual method, but it is used in containers, and some of its derived classes have important clean-up work to do in their destructor. Therefore, DataLayout requires a virtual destructor.
string vrs::DataLayout::asJson | ( | const JsonFormatProfileSpec & | profile = JsonFormatProfileSpec() | ) | const |
Generate json representation of this layout, using a profile telling which fields to include, and other presentation options.
profile | Formatting profile. |
string vrs::DataLayout::asJson | ( | JsonFormatProfile | profile | ) | const |
Generate json representation of this layout, using a profile telling which fields to include, and other presentation options.
profile | Formatting profile. |
void vrs::DataLayout::collectVariableDataAndUpdateIndex | ( | ) |
Collect all the variable-size fields in the varData_ buffer.
void vrs::DataLayout::collectVariableDataAndUpdateIndex | ( | void * | destination | ) |
Collect variable-size data to the buffer specified.
destination | Pointer to the buffer. The buffer must be at least getVarDataSizeNeeded() large. |
bool vrs::DataLayout::copyClonedDataPieceValues | ( | const DataLayout & | originalLayout | ) |
When a layout was cloned from another layout - this must be true -, this method will copy or stage all the data piece values from the original layout, so edits can be made and a new record generated with the DataLayout, using the values from originalLayout when possible.
originalLayout | cloned datalayout from which DataPiece values need to be copied. |
const DataPieceArray< T > * vrs::DataLayout::findDataPieceArray | ( | const string & | label, |
size_t | arraySize | ||
) | const |
Find a field of type DataPieceArray<T> by name.
label | Text name of the field (not the variable name). |
const DataPieceString * vrs::DataLayout::findDataPieceString | ( | const string & | label | ) | const |
Find a field of type DataPieceString by name.
label | Text name of the field (not the variable name). |
template const DataPieceStringMap< string > * vrs::DataLayout::findDataPieceStringMap< string > | ( | const string & | label | ) | const |
Find a field of type DataPieceStringMap<T> by name.
label | Text name of the field (not the variable name). |
const DataPieceValue< T > * vrs::DataLayout::findDataPieceValue | ( | const string & | label | ) | const |
Find a field of type DataPieceValue<T> by name.
label | Text name of the field (not the variable name). |
template const DataPieceVector< string > * vrs::DataLayout::findDataPieceVector< string > | ( | const string & | label | ) | const |
Find a field of type DataPieceVector<T> by name.
label | Text name of the field (not the variable name). |
void vrs::DataLayout::forEachDataPiece | ( | const std::function< void(const DataPiece *)> & | , |
DataPieceType | type = DataPieceType::Undefined |
||
) | const |
Iterate over the different data piece elements of a DataLayout.
callback | a function to call for each element found. |
type | filter to select only an element type, of UNDEFINED for no filtering. |
size_t vrs::DataLayout::getAvailableFixedDataPiecesCount | ( | ) | const |
For debugging: get the number of fixed size data pieces available. When a datalayout is mapped on another one (when reading from disk), some pieces might not be available, because the datalayout read from disk might not have them.
size_t vrs::DataLayout::getAvailableVarDataPiecesCount | ( | ) | const |
For debugging: get the number of variable size data pieces available. When a datalayout is mapped on another one (when reading from disk), some pieces might not be available, because the datalayout read from disk might not have them.
ContentBlock vrs::DataLayout::getContentBlock | ( | ) | const |
|
inline |
For debugging: get the number of fixed size data pieces declared.
|
inline |
For debugging: get the number of variable size data pieces declared.
|
inline |
To access the buffer for fixed-size DataPieces. No need for a const version.
|
inlineprotected |
Get pointer to a section of raw memory, by offset & size.
offset | Offset of the field in the fixed-size fields buffer. |
size | Byte count size of the field. |
|
inline |
Size required to fit all fixed size data.
void vrs::DataLayout::getRawData | ( | vector< int8_t > & | outRawData | ) | const |
Get this layout's raw data. Assumes no data needs to be collected (nothing was "staged"). In particular, can be used in RecordFormatStreamPlayer's callback to copy the layout verbatim.
|
inline |
To access the buffer for variable-size DataPieces. No need for a const version.
|
inlineprotected |
Get pointer & size of a variable-size field's data.
varPieceIndex | Index of the variable-size piece. |
outCount | Reference to set to the size in bytes of the data. |
size_t vrs::DataLayout::getVarDataSizeFromIndex | ( | ) | const |
Retrieve size of the var size pieces from the index.
Only really meaningful after variable-size pieces:
size_t vrs::DataLayout::getVarDataSizeNeeded | ( | ) | const |
|
protected |
Get the var size index.
|
protected |
Get the var size index.
|
inline |
|
protected |
After construction of a DataLayout, initializes/resets buffers to hold the DataPiece objects that have been registered for this DataLayout. This is generally, done automatically by VRS, but this might be useful for client code to manage a DataLayout creation manually. In common practice, this is probably only needed by the VRS code itself.
|
inline |
bool vrs::DataLayout::isSame | ( | const DataLayout & | otherLayout | ) | const |
Compare two layouts, and tells if all the pieces are in the same order, with the same properties (name, type, tags, etc). Does not compare actual values!
otherLayout | Layout to compare to. |
bool vrs::DataLayout::isVarDataIndexValid | ( | ) | const |
For debugging: validate that the index for the variable size data looks valid. If you think you need this in production code, please contact the VRS team...
|
static |
Create a DataLayout from a json description generated with asJson().
json | json datalayout description. |
bool vrs::DataLayout::mapLayout | ( | DataLayout & | targetLayout | ) |
Map the data pieces of this layout to that of another layout, field by field. Note that this call is fairly expensive, and it is normally not necessary to call directly. In particular, in the callback RecordFormatStreamPlayer::onDataLayoutRead(), calling mapLayout() directly can usually be avoided by using the methods RecordFormatStreamPlayer::getExpectedLayout() and RecordFormatStreamPlayer::getLegacyLayout(), which will cache the mapping for you.
targetLayout | Other DataLayout to map each DataPiece to. This is usually the layout that contains a record's actual data. |
void vrs::DataLayout::printLayout | ( | ostream & | out, |
const string & | indent = "" |
||
) | const |
Print the fields of this DataLayout, showing all known details & values. If the layout is mapped, the values are that of the mapped fields. If a field of a mapped layout wasn't successfully mapped, no value is shown.
out | Ostream to write to. |
indent | Prefix to each output line, for nested presentation. |
void vrs::DataLayout::printLayoutCompact | ( | ostream & | out, |
const string & | indent = "" |
||
) | const |
Print the values of the fields of this datalayout, in a compact form.
out | Ostream to write to. |
indent | Prefix to each output line, for nested presentation. |
|
protected |
Export the DataLayout as json, using a specific profile.
jsonWrapper | Wrapper around a json type (to isolate any 3rd party library dependency). |
profile | Profile describing what information needs to be exported as json. |
void vrs::DataLayout::stageCurrentValues | ( | ) |
Take the values of the variable size fields and stage them. This is basically the opposite of collectVariableDataAndUpdateIndex(). This is useful if you have read a DataLayout from disk, and want to edit some fields to write an edited version of the DataLayout.