Daqling Data Types
In this section the concepts of inner and outer datatypes will be used.
Outer datatype: Wrapper-types managing the lifetime of the inner datatype. Derivatives of the DataType class.
Inner datatype: Datatypes storing the actual data fragments. passed as template parameter to an outer Datatype.
Inner datatypes
Inner objects of type T
, must have the following functions available:
size():size_t
- returning the size of the object in bytes.data():void*
- returning a pointer to the memory section containing the inner objects data to be sent.T(void* _data, size_t _size)
- constructor initializing the object with the data contained in the memory block pointed to by_data
with the size_size
.T()
- default constructor.
Outer datatypes
The DAQling DataType
class provides a common abstract baseclass to use for all types of datastructures, that is to be used along with the DAQling connections and queues.
This class has three important features:
- The queues and connections are based on this baseclass, and made to work with all properly implemented subclasses.
- The
Datatype
class provides adetach()
function, which releases ownership of the internal datastructure. Along with this function comes thefree()
function, which should manually be called after adetach()
call to deallocate the internal data. If detach isn’t called, the destructor of the datatype will deallocate the internal memory. - The
Datatype
class provides thevoid * data()
andsize_t size()
functions, which are used to give access to the memory chunk of the internal data. These are used by the specific connection implementations, to send the actual data between modules.
DAQling provides two generic standard Datatype
subclasses. The DataFragment<T>
and TemplatedSharedDataType<T>
.
These classes manages the lifetime of an inner T object.
DataFragment<T>
Data type made for holding a an object which is stored contiguous in memory.
The DataFragment
is a wrapper that handles the lifetime issues of the inner object. Meanwhile the object is easily accessible, through pointer semantics (operator->
and get()
functions).
TemplatedSharedDataType<T>
Roughly similar to DataFragment<T>
, but stores the inner object in a std::shared_ptr
.
This allows for light copying utilizing shared_ptr
functionality, which can be used in cases where light copying can save resources, but you still want the object available afterwards, so std::move
is not an option. A common case of this is when trying to send an object from the modules in a while-loop until the send()
succeeds. Instead of copy-creating a new copy of the inner object and passing it to send()
, repeating this until send()
succeeds, copying the shared_ptr
to the inner data is a better solution. This is done by first invoking the make_shared()
method of the TemplatedSharedDataType
, and afterwards using copy assignment/construction on the object.
The downside of this functionality is that the shared_ptr
used to keep track of when the inner object can be safely deallocated, has increased overhead compared to the raw pointer implementation of DataFragment<T>
. Therefore TemplatedSharedDataType<T>
should only be used in cases where you can benefit from the shared_ptr
semantics, and even then, there is no guarantee that this will be more efficient for your particular use case.
Class diagram of the DAQling Data Types:
Registration and use of parameterized DataTypes
To use a parameterized type of one of the subclasses, just create the type in a DAQling module, and pass it to the send or receive method of the daqling::core::ConnectionSubManager
instance. E.g.:
struct myDataStruct{
public:
myDataStruct(){};
myDataStruct(void* data,size_t size):msg(data,data+size){}
std::string msg;
inline size_t size() { return sizeof(msg);}
inline void *data() { return this; }
};
auto msg = DataFragment<myDataStruct>(new myDataStruct());
msg->msg="Hello world";
uint channel_no = 0;
m_connections.send(channel_no,msg);
It is possible for developers to derive directly from DataType or one of the subclasses, to create custom data structures, or to extend these, to allow for conversion between a receiving and sending type for example.