Commit 805da350 authored by Matteo Ferrari's avatar Matteo Ferrari
Browse files

Merge branch 'wip-multi-array' into 'master'

Add MultiArray support

See merge request !14
parents b1fe7c4d 5daf3a42
Pipeline #2810449 passed with stages
in 13 minutes and 40 seconds
......@@ -8,8 +8,11 @@
#include "ADDHClientHandler.h"
#include <cmath>
#include <sstream>
#include <utility>
#include <boost/algorithm/string.hpp>
#include <DIMData.h>
#include <DIMUtils.hpp>
#include <easylogging++.h>
......@@ -65,7 +68,9 @@ void ADDHClientHandler::infoHandler()
m_inError = false;
std::lock_guard<std::mutex> lock(m_mutex);
m_data.clear();
m_data.push_back(std::move(makeValue(m_destination)));
FieldList values = makeValue(m_destination);
m_data.insert(std::end(m_data), std::begin(values),
std::end(values));
}
}
catch (const ADDHException &ex)
......@@ -141,83 +146,168 @@ void ADDHClientHandler::dataChanged(std::vector<ntof::dim::DIMData> &dataSet,
}
template<typename DestType, typename SourceType>
ADDHClientHandler::FieldList::value_type ADDHClientHandler::createADDH(
ADDHClientHandler::FieldList ADDHClientHandler::createADDH(
const std::string &name,
AdditionalDataValue::Type type,
const SourceType *data,
int count)
size_t rows,
size_t columns)
{
FieldList::value_type ret(new AdditionalDataValue(name, type, count));
for (int i = 0; i < count; i++)
FieldList ret;
for (int i = 0; i < rows; i++)
{
ret->append<DestType>(data[i]);
std::string rowName(name);
if (rows > 1)
rowName += "/Row" + std::to_string(i);
FieldList::value_type val(
new AdditionalDataValue(rowName, type, columns));
for (int j = 0; j < columns; j++)
{
val->append<DestType>(data[i * columns + j]);
}
ret.push_back(std::move(val));
}
return ret;
}
ADDHClientHandler::FieldList::value_type ADDHClientHandler::makeValue(
const std::string &name)
bool ADDHClientHandler::isFormatSupported(size_t &rows, size_t &columns)
{
std::string format(this->itsService->getFormat());
// if "|" is present, it means service is not supported (CMD or RPC)
if (format.find('|') != std::string::npos)
{
return false;
}
// Example of supported multi-array: "D:3;D3"
// Example of supported array: "D", "D:3"
// Example of not supported format: "D:3;D:4" -> dimensions are different
// "D:3;F:3" -> type are different
// "D:3;D:3;D" -> last array unknown length
rows = 1;
columns = 0;
size_t count = 0;
// Get all the items
int size = this->itsService->getSize();
if (format.at(0) == 'I' || format.at(0) == 'L')
count = size / sizeof(int32_t);
else if (format.at(0) == 'C')
count = size;
else if (format.at(0) == 'X')
count = size / sizeof(int64_t);
else if (format.at(0) == 'S')
count = size / sizeof(int16_t);
else if (format.at(0) == 'F')
count = size / sizeof(float);
else if (format.at(0) == 'D')
count = size / sizeof(double);
else
{
return false;
} // Format not supported
if (format.size() == 1)
{ // Basic Format
columns = count;
return true;
}
// Save the first type
char &dimType = format.front();
std::vector<std::string> allFormats;
boost::split(allFormats, format, boost::is_any_of(";"));
rows = allFormats.size();
for (std::string &f : allFormats)
{
std::vector<std::string> parts; // part[0] -> dimType, part[1] -> columns
boost::split(parts, f, boost::is_any_of(":"));
if (parts.size() != 2)
return false; // Strange format
if (dimType != f.front())
return false; // Different types
size_t cols;
std::istringstream iss(parts[1]);
iss >> cols;
// First time
if (columns == 0)
columns = cols;
if (columns != cols)
return false; // multi array of different sizes
}
// Check if size count is equal to rows * columns
if (count != rows * columns)
{
std::ostringstream oss;
oss << "Size doesn't reflect format structure for: " << m_destination
<< ". Format is: " << format << "."
<< " Count: " << count << ". Rows: " << rows
<< ". Columns: " << columns;
ADDH_THROW(oss.str(), 0);
}
return true;
}
ADDHClientHandler::FieldList ADDHClientHandler::makeValue(const std::string &name)
{
ntof::dim::DIMLockGuard dimLock;
std::string format(this->itsService->getFormat());
// Check if it's a complex structure
// if ";" or "|" is present, it means structure is not supported
if (format.find(';') != std::string::npos ||
format.find('|') != std::string::npos)
size_t rows, columns;
if (!isFormatSupported(rows, columns))
{
std::ostringstream oss;
oss << "Unsupported Dim format structure for: " << m_destination;
oss << "Unsupported Dim format structure for: " << m_destination
<< ". Format is: " << format;
ADDH_THROW(oss.str(), 0);
}
int size = this->itsService->getSize();
char *data = (char *) this->itsService->getData();
if (format.at(0) == 'I' || format.at(0) == 'L')
{ // L is deprecated, here for backward-compatibility
return createADDH<int32_t, int32_t>(
name, AdditionalDataValue::TypeInt32,
reinterpret_cast<const int32_t *>(data), size / sizeof(int32_t));
reinterpret_cast<const int32_t *>(data), rows, columns);
}
if (format.at(0) == 'C')
else if (format.at(0) == 'C')
{
FieldList::value_type ret(
new AdditionalDataValue(name, AdditionalDataValue::TypeChar, size));
ret->fromString(this->itsService->getString());
FieldList::value_type val(new AdditionalDataValue(
name, AdditionalDataValue::TypeChar, columns));
val->fromString(this->itsService->getString());
FieldList ret;
ret.push_back(val);
return ret;
}
if (format.at(0) == 'X')
else if (format.at(0) == 'X')
{
return createADDH<int64_t, int64_t>(
name, AdditionalDataValue::TypeInt64,
reinterpret_cast<const int64_t *>(data), size / sizeof(int64_t));
reinterpret_cast<const int64_t *>(data), rows, columns);
}
if (format.at(0) == 'S')
else if (format.at(0) == 'S')
{
return createADDH<int32_t, int16_t>(
name, AdditionalDataValue::TypeInt32,
reinterpret_cast<const int16_t *>(data), size / sizeof(int16_t));
reinterpret_cast<const int16_t *>(data), rows, columns);
}
if (format.at(0) == 'F')
else if (format.at(0) == 'F')
{
return createADDH<float, float>(name, AdditionalDataValue::TypeFloat,
reinterpret_cast<const float *>(data),
size / sizeof(float));
rows, columns);
}
if (format.at(0) == 'D')
else if (format.at(0) == 'D')
{
return createADDH<double, double>(
name, AdditionalDataValue::TypeDouble,
reinterpret_cast<const double *>(data), size / sizeof(double));
reinterpret_cast<const double *>(data), rows, columns);
}
std::ostringstream oss;
oss << "Unsupported Service Type for Basic Dim Service for: "
<< m_destination;
<< m_destination << ". Format is: " << format;
ADDH_THROW(oss.str(), 0);
}
......
......@@ -105,18 +105,29 @@ protected:
* @param[in] type ADDH Type
* @param[in] data raw pointer to data
* @param[in] count number of data items
* @return a vector with all ADDH values
*/
template<typename DestType, typename SourceType>
static FieldList::value_type createADDH(const std::string &name,
AdditionalDataValue::Type type,
const SourceType *data,
int count);
static FieldList createADDH(const std::string &name,
AdditionalDataValue::Type type,
const SourceType *data,
size_t rows,
size_t columns);
/**
* @brief create an ADDH value from a DIM data
* @brief check if the format published by the dim service is supported
* Only array amd multi-array of the same type/size are supported
* @param[out] rows number of rows
* @param[out] column number of columns
*/
bool isFormatSupported(size_t &rows, size_t &columns);
/**
* @brief create an ADDH value from a basic DIM data
* @param[in] name name of the data value where to publish the dim value
* @return a vector with all ADDH values
*/
FieldList::value_type makeValue(const std::string &name);
FieldList makeValue(const std::string &name);
/**
* @brief create an ADDH value from a DIM data
......
......@@ -45,8 +45,10 @@ protected:
CPPUNIT_TEST_SUITE(TestADDHBasicDim);
CPPUNIT_TEST(updatesSimpleValues);
CPPUNIT_TEST(updateArrayValues);
CPPUNIT_TEST(updateMultiArrayValues);
CPPUNIT_TEST(updateStringValues);
CPPUNIT_TEST(notSupportedStructure);
CPPUNIT_TEST(notSupportedMultiArrayStructure);
CPPUNIT_TEST_SUITE_END();
std::unique_ptr<DimTestHelper> m_dim;
......@@ -112,6 +114,54 @@ public:
}
}
template<typename T>
void checkMultyArrayValues(const ADDH &addh,
const std::string &service,
T expectedValue_0_0,
T expectedValue_0_1,
T expectedValue_1_0,
T expectedValue_1_1,
AdditionalDataValue::Type expectedType)
{
const ClientsMap list = addh.getClients();
ClientsMap::const_iterator it = list.find(service);
CPPUNIT_ASSERT(it != list.end());
const ADDHClient &client = it->second;
const ADDHClientHandler::FieldList values = client.client->getADDHData();
EQ(std::size_t(2), values.size());
// First Row
EQ(expectedType, values[0]->type);
EQ(std::size_t(2), values[0]->count());
if (expectedType == AdditionalDataValue::TypeFloat ||
expectedType == AdditionalDataValue::TypeDouble)
{
EQ_DBL(expectedValue_0_0, values[0]->at<T>(0), 0.01);
EQ_DBL(expectedValue_0_1, values[0]->at<T>(1), 0.01);
}
else
{
EQ(expectedValue_0_0, values[0]->at<T>(0));
EQ(expectedValue_0_1, values[0]->at<T>(1));
}
// Second Row
EQ(expectedType, values[1]->type);
EQ(std::size_t(2), values[1]->count());
if (expectedType == AdditionalDataValue::TypeFloat ||
expectedType == AdditionalDataValue::TypeDouble)
{
EQ_DBL(expectedValue_1_0, values[1]->at<T>(0), 0.01);
EQ_DBL(expectedValue_1_1, values[1]->at<T>(1), 0.01);
}
else
{
EQ(expectedValue_1_0, values[1]->at<T>(0));
EQ(expectedValue_1_1, values[1]->at<T>(1));
}
}
void updatesSimpleValues()
{
ADDH addh;
......@@ -190,6 +240,55 @@ public:
value_D[2], AdditionalDataValue::TypeDouble);
}
void updateMultiArrayValues()
{
ADDH addh;
addh.initConfigurations();
// don't ask about the const cast ...
DimInfoWaiter info("TEST/Service_D");
// Values to be published
const int32_t value_I[4] = {1, 2, 3, 4};
longlong value_X[4] = {10, 20, 30, 40};
short value_S[4] = {11, 12, 13, 14};
float value_F[4] = {50.50f, 51.50f, 52.50f, 53.50f};
double value_D[4] = {61.60, 62.60, 63.60, 64.60};
// Basic Dim Service I
DimService service_I("TEST/Service_I", "I:2;I:2", &value_I,
sizeof(value_I));
// Basic Dim Service X
DimService service_X("TEST/Service_X", "X:2;X:2", &value_X,
sizeof(value_X));
// Basic Dim Service S
DimService service_S("TEST/Service_S", "S:2;S:2", &value_S,
sizeof(value_S));
// Basic Dim Service F
DimService service_F("TEST/Service_F", "F:2;F:2", &value_F,
sizeof(value_F));
// Basic Dim Service D
DimService service_D("TEST/Service_D", "D:2;D:2", &value_D,
sizeof(value_D));
EQ(true, info.waitUpdate());
checkMultyArrayValues<int32_t>(addh, "TEST/Service_I", value_I[0],
value_I[1], value_I[2], value_I[3],
AdditionalDataValue::TypeInt32);
checkMultyArrayValues<int64_t>(addh, "TEST/Service_X", value_X[0],
value_X[1], value_X[2], value_X[3],
AdditionalDataValue::TypeInt64);
checkMultyArrayValues<int32_t>(addh, "TEST/Service_S", value_S[0],
value_S[1], value_S[2], value_S[3],
AdditionalDataValue::TypeInt32);
checkMultyArrayValues<float>(addh, "TEST/Service_F", value_F[0],
value_F[1], value_F[2], value_F[3],
AdditionalDataValue::TypeFloat);
checkMultyArrayValues<double>(addh, "TEST/Service_D", value_D[0],
value_D[1], value_D[2], value_D[3],
AdditionalDataValue::TypeDouble);
}
void updateStringValues()
{
ADDH addh;
......@@ -238,6 +337,29 @@ public:
const ADDHClientHandler::FieldList values = client.client->getADDHData();
EQ(std::size_t(0), values.size());
}
void notSupportedMultiArrayStructure()
{
ADDH addh;
addh.initConfigurations();
DimInfoWaiter info("TEST/Service_F");
// Values to be published
float value_F[3] = {50.50f, 51.50f, 52.50f};
// Basic Dim Service I (fake multi-format)
DimService service_F("TEST/Service_F", "F:1,F:2", &value_F,
sizeof(value_F));
EQ(true, info.waitUpdate());
const ClientsMap list = addh.getClients();
ClientsMap::const_iterator it = list.find("TEST/Service_F");
CPPUNIT_ASSERT(it != list.end());
const ADDHClient &client = it->second;
const ADDHClientHandler::FieldList values = client.client->getADDHData();
EQ(std::size_t(0), values.size());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestADDHBasicDim);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment