Split parts of function calling - c++

I am going to give the least extreme example I have: (Names/Identifiers are irrelevant)
session.TransmitUnsafe(
Details::Solve,
samplesCount,
pinnedInputData.GetDevicePointer( ),
Offset( pinnedOutputApproximationData.GetDevicePointer( ), outputIndex ),
Offset( SolutionData.get( ), SolutionIndices.at( outputIndex * SolutionSize ) ),
InputLength,
OutputLength,
samplesCount
);
I need to split it to something like this:
auto kernelCallingHeader = {
Details::Solve,
samplesCount
};
auto kernelArgumentsPointers = {
pinnedInputData.GetDevicePointer( ),
Offset( pinnedOutputApproximationData.GetDevicePointer( ), outputIndex ),
Offset( SolutionData.get( ), SolutionIndices.at( outputIndex * SolutionSize ) )
};
auto kernelArgumentsLengths = {
InputLength,
OutputLength,
samplesCount
};
session.TransmitUnsafe(
kernelCallingHeader...,
kernelArguments...,
kernelArgumentsLengths...
);
I can't change session.TransmitUnsafe's parameters at all, but I want to somehow structize the calling to that function. (Entirely for readability purposes)
NOTE: I used ... like expandation of variadic template function's arguments, because I am sure there's a fine way with it.
It won't harm even to have a few macros.

Related

Is there a way to create a c++ template with different return types?

I'm wondering if there's a way to write a C++ template with different return types.
My use case is a method returning the largest values from a list.
But since I'm using the Qt framework, this function shall be able to deal with numeric and QString values. When feeding this function with a list of QString, the function shall return the length of the largest string. In case of passing numeric values, the input type shall be the return type.
What I've written is this:
template< class T >
auto getMax( QList< T > aList ) -> decltype( std::is_arithmetic< T >::value ? T : int( 0 ) )
{
if ( std::is_arithmetic< T >::value )
{
T Result( aList.isEmpty() ? 0 : aList.first() );
for ( auto lElement : aList )
{
Result = std::max( Result, lElement );
}
return Result;
}
if ( std::is_same< T, QString >::value )
{
// List contains QString -> return length of largest string
int Result( aList.isEmpty() ? 0 : aList.first().length() );
for ( const QString & lrcsElement : aList )
{
Result = std::max( lrcsElement.length(), Result );
}
return Result;
}
return 0;
}
This code compiles with VS 2017.
But when I want to use the template function like this
const QString sError ( tr( "Error" ) );
const QString sWarning( tr( "Warning" ) );
const QString sInfo ( tr( "Information" ) );
const QString sDebug ( tr( "Debug " ) );
auto iMaxTextLength( SMUtils::getMax< QString >( { sError, sWarning, sInfo, sDebug } ) );
the compiler gives me some error messages:
Error C2672: "SMUtils::getMax": no matching overloaded function found.
Error C2893: Failed to specialize function template "unknown-type SMUtils::getMax(QList)".
Error C2119: "li32MaxTextLength": the type for "auto" cannot be deduced from an empty initializer.
Of course I could write a specialized getMax( QStringList ) method, but I was wondering if it's possible to use only one template function.
Is that even possible and if so, how?
Thanks,
Sören
-> decltype( std::is_arithmetic< T >::value ? T : int( 0 ) )
should be
-> std::conditional_t<std::is_arithmetic<T>::value, T, int>;
or even omit it completely and let compiler deduce it (but requires correct return types, so following if constexpr).
and your
if ( std::is_arithmetic< T >::value )
should be
if constexpr ( std::is_arithmetic< T >::value )

Google Mock : Setting argument in EXPECT_CALL

I am trying to set a class member function parameter value in Google Mock, but I get build errors and I simply don't understand what is going on. Would it be possible for someone to explain please.
The function prototype is:
virtual int recv( Socket socket
, char *buffer
, int bufferLength
, int flags ) = 0;
I am trying to test it using:
TEST_F( IPV4SocketTests, Read_SockErr_ok )
{
Mock_SocketAdaptor *adaptor = new Mock_SocketAdaptor;
char *rcvBuffer = "testingRcvWorks";
EXPECT_CALL( *adaptor, recv( testing::_, testing::_, testing::_, testing::_ ) )
.WillRepeatedly( testing::DoAll(
testing::SetArgPointee<1>( rcvBuffer ),
testing::Return( strlen( rcvBuffer ) ) ) );
The error I am getting is regarding conversion from std::get.
The problem is that rcvBuffer is a pointer. That is why you must dereference it when setting the pointee. Here is how your EXPECT_CALL should look:
EXPECT_CALL( *adaptor, recv( testing::_, testing::_, testing::_, testing::_ ) )
.WillRepeatedly( testing::DoAll(
testing::SetArgPointee<1>( *rcvBuffer ),
testing::Return( strlen( rcvBuffer ) ) ) );
EDIT:
This is the approach I've used in my projects to mock returning a char array through a pointer
used as argument. First, you need to create a custom action that will copy the contents of the
buffer (you cannot use SetArrayArgument in this case):
ACTION_TEMPLATE(SetArgNPointeeTo, HAS_1_TEMPLATE_PARAMS(unsigned, uIndex), AND_2_VALUE_PARAMS(pData, uiDataSize))
{
std::memcpy(std::get<uIndex>(args), pData, uiDataSize);
}
Then, in a test use it like this:
Mock_SocketAdaptor *adaptor = new Mock_SocketAdaptor;
char rcvBuffer[] = "testingRcvWorks";
size_t bufferSize = sizeof("testingRcvWorks");
EXPECT_CALL( *adaptor, recv( testing::_, testing::_, testing::_, testing::_ ) )
.WillRepeatedly( testing::DoAll(
SetArgNPointeeTo<0>(std::begin(rcvBuffer), bufferSize),
testing::Return( strlen( rcvBuffer ) ) ) );

Memory Corruption Due to Copy Constructor/Deleting Array?

I have a struct called SFrame which contains many elements, notably 2 elements which are of type unsigned char*. I create a member variable of this struct in my class but I newly initialize it on each iteration in a function in my class (except for when a certain boolean is true). I do this in the following manner:
if (false == m_bRemainderNeedsProcessing)
{
// ... calls before and after the initialization are unimportant and not shown
m_sFrame = SFrame();
}
Then I pass m_sFrame to a function to assign some of its elements and then I need to assign an unsigned char array to my pszMessage variable in my struct.
m_sFrame.iMessageSize = m_sFrame.iPayloadLength;
m_sFrame.iOriginalMessageSize = m_sFrame.iPayloadLength;
m_sFrame.pszMessage = new unsigned char[m_sFrame.iPayloadLength + Constants::RSSL_DECODE_PADDING];
m_sFrame.pszOriginalMessage = new unsigned char[m_sFrame.iPayloadLength + Constants::RSSL_DECODE_PADDING];
These SFrame instances are stored in a vector of SFrames i.e.
std::vector<SFrame>;
I want to be able to reuse m_sFrame for each iteration but I have to ensure that if I am going to clear the contents of the SFrame, that when I store it inside the vector, the SFrame is copied into the vector without losing it's assigned values. For this I create a copy constructor for SFrame:
I have attached an image of part of the SFrame's copy constructor.
At the end of my function, I clear the memory in the pszMessage (and the pszOriginalMessage which is almost the same) by doing the following:
ClearMemory(m_sFrame.pszMessage);
Where the ClearMemory function does the following:
void CPCAPParser::ClearMemory(unsigned char *pszBuffer)
{
if(pszBuffer != NULL)
{
delete [] pszBuffer;
}
}
Thee problem is, this function seems to be deleting more than it should do.... because after many iterations, I get an unhandled exception: Access Violation...
I've attached a few images that might help convey what the problem is. Really need help with this :(, if anyone needs me to add more details let me know.
Thanks
http://imageshack.com/f/pduGDLGZp (Constants::RSSL_DECODE_PADDING has length 7 so there are 13 bytes in total which have been set - made evident at the start of the memory block).
http://imageshack.com/f/exRaaEmip - Where I am calling ClearMemory (the memory address is obviously still the same).
I would post more images but I don't have enough rep...
SFrame:
struct SFrame
{
int* ipTemp_int_ptr;
int* ipTemp_int_ptr_actual;
int* piTimestampPos;
int* piOffset;
int iIP_Header_Length;
int iTCP_Header_Length;
int iTCP_Source_Port;
int iTCP_Dest_Port;
long long uiSequenceNumber;
long long uiInitialSequenceNumber;
long long uiAckNumber;
int iIp_total_length;
int iActual_frame_length;
int iOriginal_frame_length;
int iCaptured_frame_length;
int iTotalPayloadLength;
int iTotalMsgLoad;
int iPayloadLength;
int iBytesComplete;
int iFragmentID;
int iRemainder;
int iMessageSize;
int iOriginalMessageSize;
long long iNextExpectedSequenceNum;
std::string strSourceAddress;
std::string strDestAddress;
std::string strTimestamp;
unsigned char* pszMessage;
unsigned char* pszOriginalMessage;
unsigned int uiClientID;
int iStartOfRemainder;
int iAccumulatedMsgLength;
SFrame() : ipTemp_int_ptr ( NULL ),
ipTemp_int_ptr_actual ( NULL ),
piTimestampPos ( NULL ),
piOffset ( NULL ),
pszMessage ( NULL ),
pszOriginalMessage ( NULL ),
iIP_Header_Length( 0 ),
iTCP_Header_Length ( 0 ),
iTCP_Source_Port ( 0 ),
iTCP_Dest_Port ( 0 ),
iIp_total_length ( 0 ),
iActual_frame_length ( 0 ),
iOriginal_frame_length ( 0 ),
iCaptured_frame_length ( 0 ),
uiSequenceNumber( 0 ),
uiInitialSequenceNumber ( 0 ),
uiAckNumber( 0 ),
iPayloadLength ( 0 ),
iNextExpectedSequenceNum ( 0 ),
uiClientID ( 0 ),
iMessageSize ( 0 ),
iOriginalMessageSize ( 0 ),
iFragmentID( 0 ),
iTotalPayloadLength( 0 ),
iBytesComplete( 0 ),
iAccumulatedMsgLength ( 0 ),
iRemainder ( 0 ),
iStartOfRemainder( 0 ),
iTotalMsgLoad ( 0 )
{
}
SFrame(const SFrame &c_rSrc)
{
*this = c_rSrc;
}
SFrame &SFrame::operator=(const SFrame &c_rSrc)
{
iIP_Header_Length = c_rSrc.iIP_Header_Length;
iTCP_Header_Length = c_rSrc.iTCP_Header_Length;
iTCP_Source_Port = c_rSrc.iTCP_Source_Port;
iTCP_Dest_Port = c_rSrc.iTCP_Dest_Port;
iIp_total_length = c_rSrc.iIp_total_length;
iActual_frame_length = c_rSrc.iActual_frame_length;
iOriginal_frame_length = c_rSrc.iOriginal_frame_length;
iCaptured_frame_length = c_rSrc.iCaptured_frame_length;
iPayloadLength = c_rSrc.iPayloadLength;
uiSequenceNumber = c_rSrc.uiSequenceNumber;
uiInitialSequenceNumber = c_rSrc.uiInitialSequenceNumber;
uiAckNumber = c_rSrc.uiAckNumber;
iNextExpectedSequenceNum = c_rSrc.iNextExpectedSequenceNum;
uiClientID = c_rSrc.uiClientID;
iFragmentID = c_rSrc.iFragmentID;
iMessageSize = c_rSrc.iMessageSize;
iOriginalMessageSize = c_rSrc.iOriginalMessageSize;
iTotalPayloadLength = c_rSrc.iTotalPayloadLength;
iBytesComplete = c_rSrc.iBytesComplete;
iAccumulatedMsgLength = c_rSrc.iAccumulatedMsgLength;
iRemainder = c_rSrc.iRemainder;
iStartOfRemainder = c_rSrc.iStartOfRemainder;
iTotalMsgLoad = c_rSrc.iTotalMsgLoad;
strSourceAddress = c_rSrc.strSourceAddress;
strDestAddress = c_rSrc.strDestAddress;
strTimestamp = c_rSrc.strTimestamp;
pszMessage = (c_rSrc.pszMessage == NULL) ? NULL : new unsigned char[c_rSrc.iMessageSize];
pszOriginalMessage = (c_rSrc.pszOriginalMessage == NULL) ? NULL : new unsigned char[c_rSrc.iOriginalMessageSize];
if(pszMessage != NULL)
{
memcpy(pszMessage, c_rSrc.pszMessage, c_rSrc.iMessageSize);
}
if(pszOriginalMessage != NULL)
{
memcpy(pszOriginalMessage, c_rSrc.pszOriginalMessage, c_rSrc.iOriginalMessageSize);
}
return *this;
}
~SFrame()
{
delete [] pszMessage;
delete [] pszOriginalMessage;
}
};
Your problem is that your SFrame struct is not safely asignable, yet you are placing instances of this in a std::vector that will make copies.
Either:
Add a working user-defined copy constructor and assignment operator to your SFrame struct or
Replace the pointer members with std::vector.
You have many members in your struct now. If you miss just one in your copy constructor, or your handling of allocated memory is faulty, you will have a broken copy. Since a vector<SFrame> will create copies, having broken copies is a no-go with vector<SFrame>.
So instead of this, here is the fix using option 2:
#include <vector>
struct SFrame
{
std::vector<int> ipTemp_int_ptr;
std::vector<int> ipTemp_int_ptr_actual;
std::vector<int> piTimestampPos;
std::vector<int> piOffset;
int iIP_Header_Length;
int iTCP_Header_Length;
int iTCP_Source_Port;
int iTCP_Dest_Port;
long long uiSequenceNumber;
long long uiInitialSequenceNumber;
long long uiAckNumber;
int iIp_total_length;
int iActual_frame_length;
int iOriginal_frame_length;
int iCaptured_frame_length;
int iTotalPayloadLength;
int iTotalMsgLoad;
int iPayloadLength;
int iBytesComplete;
int iFragmentID;
int iRemainder;
int iMessageSize;
int iOriginalMessageSize;
long long iNextExpectedSequenceNum;
std::string strSourceAddress;
std::string strDestAddress;
std::string strTimestamp;
std::vector<unsigned char> pszMessage;
std::vector<unsigned char> pszOriginalMessage;
unsigned int uiClientID;
int iStartOfRemainder;
int iAccumulatedMsgLength;
SFrame() :
iIP_Header_Length( 0 ),
iTCP_Header_Length ( 0 ),
iTCP_Source_Port ( 0 ),
iTCP_Dest_Port ( 0 ),
iIp_total_length ( 0 ),
iActual_frame_length ( 0 ),
iOriginal_frame_length ( 0 ),
iCaptured_frame_length ( 0 ),
uiSequenceNumber( 0 ),
uiInitialSequenceNumber ( 0 ),
uiAckNumber( 0 ),
iPayloadLength ( 0 ),
iNextExpectedSequenceNum ( 0 ),
uiClientID ( 0 ),
iMessageSize ( 0 ),
iOriginalMessageSize ( 0 ),
iFragmentID( 0 ),
iTotalPayloadLength( 0 ),
iBytesComplete( 0 ),
iAccumulatedMsgLength ( 0 ),
iRemainder ( 0 ),
iStartOfRemainder( 0 ),
iTotalMsgLoad ( 0 )
{
}
};
Note that the copy constructor and assignment operator (and destructor) are now gone, thus making the code a lot easier to handle, as well as not having a chance of missing any of the members during the copy. Instead we let the compiler generate the copy, and the compiler will always get every member copied.
Now, your code base that uses the struct has to be recompiled, and you will inevitably get compiler errors. However those errors are usually very easy to fix. Most will probably require you to
Remove the lines with delete [] somepointer; where somePointer is now a vector and
If passing a pointer to the beginning of the buffer, you pass &vector[0] or vector.data(), since a vector is basically a wrapper for new[]/delete[].
Going back to your original code, one issue with your assignment operator is that you failed to delete the previous memory allocated, thus you have a memory leak. Also, you didn't check for self-assignment, given the way you wrote the copy operations. However, this may not have been the only error, as we didn't see how you're using these SFrame instances.
Therefore it may be better to change to vector, fix the compiler errors, rebuild and test your app.

generate unique key for std::map

I have a map with a string as the key and stores lambdas.
I've so far tried
std::map <int, auto> callbackMap
And put a lambda where there isn't one with the same number already. Is this possible ? I keep getting errors saying functions can't have auto as constructors.
It's because auto is just a compile time "feature" that converts the type you need to a very defined type! You are maybe confusing it with a "variant" type... it doesn't work this way.
auto X = 3;
It doesn't mean X is a "variant". It's like the compiler converts it to:
int X = 3;
So, notice that X has a very defined type.
You CAN store functions (lambda is the operator) in your map, no problem. But with your std::function<...> very defined. Example:
std::map< int, std::function< int( int ) > > callbackMap;
callbackMap[ 0 ] = std::function< int( int ) >( [] ( int a ) { return a + 1; } );
callbackMap[ 1 ] = std::function< int( int ) >( [] ( int a ) { return a - 1; } );
callbackMap[ 2 ] = std::function< int( int ) >( [] ( int a ) { return a * 2; } );
callbackMap[ 3 ] = std::function< int( int ) >( [] ( int a ) { return a / 2; } );
Notice that you still need to know the signature of your functions... (here in my example int( int a ), but you can define of course the way you want).
If you decide to store "pointers to functions" you will have the same problem. You have to know the signature! Nothing different.

QAbstractItemModel + ModelTest::rowsInserted ASSERTion problem

I'm trying to debug my model (QAbstractItemModel) with ModelTest. And I can't understand one assertion.
There are two slots in ModelTest that intercept signals generated by my model.
ModelTest::rowsAboutToBeInserted
ModelTest::rowsInserted
Slot/function 1 looks like this
void ModelTest::rowsAboutToBeInserted ( const QModelIndex &parent, int start, int end )
{
Changing c;
// ...
c.last = model->data ( model->index ( start - 1, 0, parent ) );
c.next = model->data ( model->index ( start, 0, parent ) );
insert.push ( c );
}
And slot 2 looks like this
void ModelTest::rowsInserted ( const QModelIndex & parent, int start, int end )
{
Changing c = insert.pop();
// other asserts ...
(*) Q_ASSERT ( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) );
}
I don't understand dla last assertion (*). Lets assume that in my app I add 1 row.
This row is the only row that is stored in my model. So the row number would be 0.
In my model before adding the row I call
beginInsertRows(parentIndex, 0, 0);
So why does modeltest require
model->data ( model->index ( start, 0, parent ) )
to be equal to
model->data ( model->index ( end + 1, 0, c.parent ) )
What am I missing here ? Please help :)
The idea behind this assert is to check if first row after added ones was correctly moved. If there are some rows after inserted ones, then their data are compared. If there aren't any, your model should both in the line
c.next = model->data ( model->index ( start, 0, parent ) );
and in
Q_ASSERT ( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) );
should return invalid (empty) QVariant. If both return empty QVariant (as they should) assertion succedes, thus providing some level of error-checking even in case of no rows after currently inserted.