how to log size of array with ilog - c++

I have this code and just want to log size of array :
auto owner = abi_data["owner"].as<chain::authority>();
auto arrSize = std::size(owner.keys);
ilog(arrSize);
But have an error :
error: no matching constructor for initialization of 'fc::log_message'
How can i fix it?
I understand that the c ++ methodology is very specific. Therefore, I will expand my question and thus grope the way.
how to get public key string from auto owner.
i tried :
std::string k = owner.keys[0].key
error: no viable conversion from 'eosio::chain::public_key_type' (aka 'fc::crypto::public_key') to 'std::string'
I don’t understand how I should transform all this for correct work and get correct public key and replace hardcoded old_account_name .
full code :
else if (action.name == N(newaccount)) {
auto new_account_name = abi_data["newact"].as<chain::name>().to_string();
auto creator = abi_data["creator"].as<chain::name>().to_string();
std::string old_account_name = "EOS7ea3Dj15nUkKz3diU7BmE5FV5aNKsBKL6WScwEaKzNwDp41SSU";
auto owner = abi_data["owner"].as<chain::authority>();
auto active = abi_data["active"].as<chain::authority>();
ilog("new_account_name: " + new_account_name + " ,creator: " + creator);
*m_session << "UPDATE user_address SET address = :nan WHERE crypto_currency_asset_id = :ai AND address = :oan",
soci::use(new_account_name, "nan"),
soci::use(old_account_name, "oan"),
soci::use(asset_id, "ai");
}

FIXED!
auto arrSize = sizeof(owner.keys)/sizeof(owner.keys[0]);
auto ownerPK = static_cast<std::string>(owner.keys[0].key);

Related

open62541 client fails when calling method with custom datatype input argument

I'm using open62541 to connect to an OPC/UA server and I'm trying to call methods that a certain object on that server provides. Those methods have custom types as input arguments; for example, the following method takes a structure of three booleans:
<opc:Method SymbolicName="SetStatusMethodType" ModellingRule="Mandatory">
<opc:InputArguments>
<opc:Argument Name="Status" DataType="VisionStatusDataType" ValueRank="Scalar"/>
</opc:InputArguments>
<opc:OutputArguments />
</opc:Method>
Here, VisionStatusDataType is the following structure:
<opc:DataType SymbolicName="VisionStatusDataType" BaseType="ua:Structure">
<opc:ClassName>VisionStatus</opc:ClassName>
<opc:Fields>
<opc:Field Name="Camera" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="StrobeController" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="Server" DataType="ua:Boolean" ValueRank="Scalar"/>
</opc:Fields>
</opc:DataType>
Now, when calling the method, I'm encoding the data into an UA_ExtensionObject, and wrap that one as an UA_Variant to provide it to UA_Client_call. The encoding looks like this:
void encode(const QVariantList& vecqVar, size_t& nIdx, const DataType& dt, std::back_insert_iterator<std::vector<UAptr<UA_ByteString>>> itOut)
{
if (dt.isSimple())
{
auto&& qVar = vecqVar.at(nIdx++);
auto&& uaVar = convertToUaVar(qVar, dt.uaType());
auto pOutBuf = create<UA_ByteString>();
auto nStatus = UA_encodeBinary(uaVar.data, dt.uaType(), pOutBuf.get());
statusCheck(nStatus);
itOut = std::move(pOutBuf);
}
else
{
for (auto&& dtMember : dt.members())
encode(vecqVar, nIdx, dtMember, itOut);
}
}
UA_Variant ToUAVariant(const QVariant& qVar, const DataType& dt)
{
if (dt.isSimple())
return convertToUaVar(qVar, dt.uaType());
else
{
std::vector<UAptr<UA_ByteString>> vecByteStr;
auto&& qVarList = qVar.toList();
size_t nIdx = 0UL;
encode(qVarList, nIdx, dt, std::back_inserter(vecByteStr));
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.uaType()->typeId;
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}
UA_Variant uaVar;
UA_Variant_init(&uaVar);
UA_Variant_setScalar(&uaVar, pExtObj, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
return uaVar;
}
}
The DataType class is a wrapper for the UA_DataType structure; the original open62541 type can be accessed via DataType::uaType().
Now, once a have the variant (containing the extension object), the method call looks like this:
auto uavarInput = ToUAVariant(qvarArg, dtInput);
UA_Variant* pvarOut;
size_t nOutSize = 0UL;
auto nStatus = UA_Client_call(m_pClient, objNode.nodeId(), m_uaNodeId, 1UL, &uavarInput, &nOutSize, &pvarOut);
The status is 2158690304, i.e. BadInvalidArgument according to UA_StatusCode_name.
Is there really something wrong with the method argument? Are we supposed to send ExtensionObjects, or what data type should the variant contain?
Is it possible that the server itself (created using the .NET OPC/UA stack) is not configured correctly?
N.B., the types here are custom types; that is, the encoding is done manually (see above) by storing the byte representation of all members next to each other in an UA_ByteString - just the opposite of what I'm doing when reading variables or output arguments, which works just fine.
The problem is the typeId of the encoded object. For the server in order to understand the received data, it needs to know the NodeId of the encoding, not the actual NodeId of the type itself. That encoding can be found by following the HasEncoding reference (named "Default Binary") of the type:
auto pRequest = create<UA_BrowseRequest>();
auto pDescr = pRequest->nodesToBrowse = UA_BrowseDescription_new();
pRequest->nodesToBrowseSize = 1UL;
pDescr->nodeId = m_uaNodeId;
pDescr->resultMask = UA_BROWSERESULTMASK_ALL;
pDescr->browseDirection = UA_BROWSEDIRECTION_BOTH;
pDescr->referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASENCODING);
auto response = UA_Client_Service_browse(m_pClient, *pRequest);
for (auto k = 0UL; k < response.resultsSize; ++k)
{
auto browseRes = response.results[k];
for (auto n = 0UL; n < browseRes.referencesSize; ++n)
{
auto browseRef = browseRes.references[n];
if (ToQString(browseRef.browseName.name).contains("Binary"))
{
m_nodeBinaryEnc = browseRef.nodeId.nodeId;
break;
}
}
}
Once you have that NodeId, you pass it to UA_ExtensionObject::content::encoded::typeId:
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.encoding();
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}

C++ FlatBuffers - Assertion failed: (finished), function Finished

Here is my schema:
namespace Vibranium;
enum GameObject_Type:uint { STATIC = 0 }
table GameObjectDatabase
{
gameobjects:[GameObjectsTemplate];
}
table GameObjectsTemplate
{
id:int;
name:string;
prefab:string;
type:GameObject_Type;
position_x:float;
position_y:float;
position_z:float;
rotation_x:float;
rotation_y:float;
rotation_z:float;
map_id:int;
event_id:int;
}
root_type GameObjectDatabase;
Here is my code:
flatbuffers::FlatBufferBuilder fbb;
std::vector<flatbuffers::Offset<Vibranium::GameObjectsTemplate>> gameobjects_template;
Field* fields = result->Fetch();
auto id = fields[0].GetInt32();
auto name = fbb.CreateString(fields[1].GetString());
auto prefab = fbb.CreateString(fields[2].GetString());
auto type = static_cast<Vibranium::GameObject_Type>(fields[3].GetInt32());
auto position_x = fields[5].GetFloat();
auto position_y = fields[6].GetFloat();
auto position_z = fields[7].GetFloat();
auto rotation_x = fields[8].GetFloat();
auto rotation_y = fields[9].GetFloat();
auto rotation_z = fields[10].GetFloat();
auto map_id = fields[11].GetInt32();
auto event_id = fields[12].GetInt32();
auto go1 = Vibranium::CreateGameObjectsTemplate(fbb, id, name, prefab, type,position_x,position_y,position_z, rotation_x,rotation_y,rotation_z,map_id,event_id);
gameobjects_template.push_back(go1);
this->_container.push_back(go1);
auto go_db = fbb.CreateVector(gameobjects_template);
Vibranium::GameObjectDatabaseBuilder go_builder(fbb);
go_builder.add_gameobjects(go_db);
go_builder.Finish();
auto gt = Vibranium::GetGameObjectDatabase(fbb.GetBufferPointer());
I get this error:
Assertion failed: (finished), function Finished, file /opt/homebrew/include/flatbuffers/flatbuffers.h, line 1226.
It is caused by this line:
auto gt = Vibranium::GetGameObjectDatabase(fbb.GetBufferPointer());
Why is that and how can I fix it?
If you get an assert, it is always good to check the assert code, it may give you a hint as to why:
void Finished() const {
// If you get this assert, you're attempting to get access a buffer
// which hasn't been finished yet. Be sure to call
// FlatBufferBuilder::Finish with your root table.
// If you really need to access an unfinished buffer, call
// GetCurrentBufferPointer instead.
FLATBUFFERS_ASSERT(finished);
}

C++ double free or corruption (out)

Here is my code:
#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
std::vector<AccountsStruct> accounts;
AccountsStruct accountsStruct;
for (Row row : res.fetchAll()){
accountsStruct.id = row[0].get<int>();
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
accountsStruct.state = row[4].get<int>();
accountsStruct.name = row[5].get<std::string>();
accountsStruct.lastname = row[6].get<std::string>();
accountsStruct.country = row[7].get<std::string>();
accountsStruct.dob_month = row[8].get<int>();
accountsStruct.dob_day = row[9].get<int>();
accountsStruct.dob_year = row[10].get<int>();
accountsStruct.balance = row[11].get<double>();
accountsStruct.created_at = row[12].get<std::string>();
accountsStruct.updated_at = row[13].get<std::string>();
accountsStruct.account_role = row[15].get<int>();
accountsStruct.rank = row[16].get<int>();
accountsStruct.playerRole = row[17].get<int>();
Data.emplace_back(&accountsStruct);
}
std::cout << "SIZE: " << Data.size() << std::endl;
}
Data is std::vector<std::unique_ptr<DataStruct>> Data;.
To add into the vector I call Data.emplace_back(&accountsStruct); which leads me to the following output:
SIZE: 2
double free or corruption (out)
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
I am sure this line Data.emplace_back(&accountsStruct); is causing the issue. Why? How can I fix it?
You're trying to free memory not allocated with new (stack memory, to be precise).
std::vector<std::unique_ptr<DataStruct>> Data;
AccountsStruct accountsStruct; // <-- a stack variable
Data.emplace_back(&accountsStruct); // <-- an instance of unique_ptr is created using the address of accountsStruct
So when Data is destroyed, unique_ptr calls delete on that pointer (not good!!).
I can think of 2 possible solutions:
Allocate accountsStruct on the heap using std::make_unique:
for (auto& row : res.fetchAll()) {
Data.emplace_back(std::make_unique<AccountsStruct>()); // allocate a new instance on the heap
AccountsStruct& accountsStruct = *Data.back(); // get a reference to that instance
accountsStruct.id = row[0].get<int>(); // fill it normally ...
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
. . .
Simplify Data to store by-value: std::vector<DataStruct> Data;
for (auto& row : res.fetchAll()) {
Data.emplace_back(); // allocates a new instance of AccountsStruct in-place
AccountsStruct& accountsStruct = Data.back(); // get a reference to that instance
accountsStruct.id = row[0].get<int>(); // fill it normally ...
accountsStruct.email = row[1].get<std::string>();
accountsStruct.warTag = row[2].get<std::string>();
. . .
Data should contain a std::unique_ptr<AccountsStruct>. I'm afraid, unique_ptr can't be created from AccountsStruct.
So, create struct dynamically, fills by data, create unique_ptr from pointer and add it to vector.
The problem in your code is that you provide an address of a local variable to the constructor of std::unique_ptr.
I assume that Data is std::vector<std::unique_ptr<AccountsStruct>> If AccountsStruct has constructor with no arguments, you can try this:
#include "Accounts.h"
using namespace Vibranium;
void Accounts::LoadTable(RowResult &res) {
std::vector<AccountsStruct> accounts;
// create an instance in the vector and get a reference to it
// auto will be std::unique_ptr<AccountsStruct>&;
auto &accountsStruct = Data.emplace_back();
// work with that reference
for (Row row : res.fetchAll()){
accountsStruct->id = row[0].get<int>();
accountsStruct->email = row[1].get<std::string>();
accountsStruct->warTag = row[2].get<std::string>();
accountsStruct->state = row[4].get<int>();
accountsStruct->name = row[5].get<std::string>();
accountsStruct->lastname = row[6].get<std::string>();
accountsStruct->country = row[7].get<std::string>();
accountsStruct->dob_month = row[8].get<int>();
accountsStruct->dob_day = row[9].get<int>();
accountsStruct->dob_year = row[10].get<int>();
accountsStruct->balance = row[11].get<double>();
accountsStruct->created_at = row[12].get<std::string>();
accountsStruct->updated_at = row[13].get<std::string>();
accountsStruct->account_role = row[15].get<int>();
accountsStruct->rank = row[16].get<int>();
accountsStruct->playerRole = row[17].get<int>();
}
std::cout << "SIZE: " << Data.size() << std::endl;
}
If AccountsStruct is derived from DataStruct you can use:
data.emplace_back(std::make_unique<AccountData>());

What is invalid SourceLocation in clang and how to interact with it?

I need to replace some variable declarations with others.
For example
int a = 5;
becomes
T<int> a = 5;
More generic
X a = _const;
becomes
T<X> a = _const;
I tried to implement an ASTVisitor descendant in clang:
bool VisitVarDecl(Decl *f) {
if (VarDecl* VD = dyn_cast_or_null<VarDecl>(f)){
Expr* init = VD->getInit();
SourceRange definition = VD->getDefinition()->getSourceRange();
FullSourceLoc exprLoc = ctx.getFullLoc(init->getLocStart());
FullSourceLoc vLoc = ctx.getFullLoc(VD->getLocStart());
...
I want to replace the definition of variable in the next way:
TheRewriter.ReplaceText(VD->getLocStart(), exprLoc.getSpellingColumnNumber()-vLoc.getSpellingColumnNumber(), someSting);
But any call exprLoc.getSpellingColumnNumber() leads to segmentation fault. For example I just try to print exprLoc.getSpellingColumnNumber():
llvm::outs()<< "init start at "
<<exprLoc.getSpellingColumnNumber(&isValid)
<<" is "<<(isValid?"valid ":"invalid ")
<<", decl start at "
<<vLoc.getSpellingColumnNumber()
<<".\n";
And output is
init start at 9 is invalid , decl start at 1.
<…>
Segmentation fault
What does it mean “invalid” SourceLocation and how to interact with it?

Preferred way of filling up a C++ vector of structs

Alternative 1, reusing a temporary variable:
Sticker sticker;
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
board.push_back(sticker);
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
board.push_back(sticker);
Alternative 2, scoping the temporary variable:
{
Sticker sticker;
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
board.push_back(sticker);
}
{
Sticker sticker;
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
board.push_back(sticker);
}
Alternative 3, writing straight to the vector memory:
{
board.push_back(Sticker());
Sticker &sticker = board.back();
sticker.x = x + foreground.x;
sticker.y = foreground.y;
sticker.width = foreground.width;
sticker.height = foreground.height;
}
{
board.push_back(Sticker());
Sticker &sticker = board.back();
sticker.x = x + outline.x;
sticker.y = outline.y;
sticker.width = outline.width;
sticker.height = outline.height;
}
Which approach do you prefer?
Edit: For the sake of this discussion, assume that the assignments have to be made one by one outside of a constructor
My option - give Sticker a constructor that takes the parameters. then:
board.push_back( Sticker( outline.x, foo.bar, etc. ) );
Edit: Code to illustrate constructor parameter names:
#include <iostream>
using namespace std;
struct S {
int a, b;
S( int a, int b ) : a(a), b(b) {
}
};
int main() {
S s( 1, 2);
cout << s.a << " " << s.b << endl;
}
board.resize(sticker_count);
Then iterate through all the vector and set parameters.
Alternative 1. Why create a scope just for a variable? There is usually an enclosing scope nearby (at the minimum, you should keep your functions/procedures small so that will scope it).
Why? You can create a shorter variable name e.g. st in this case. Since the assignment will be nearby there should be no loss in clarity. Actually it will look simpler and cleaner.
Also, if the vector needs to be dereferenced/accessed from several other levels of indirection, then it will also simplify the code.
How about winforms style:
// Class members
Sticker sticker1;
Sticker sticker2;
Board board;
// Initialization
void InitBoard()
{
sticker1.x = x + foreground.x;
sticker1.y = foreground.y;
sticker1.width = foreground.width;
sticker1.height = foreground.height;
sticker2.x = x + outline.x;
sticker2.y = outline.y;
sticker2.width = outline.width;
sticker2.height = outline.height;
// Add to board
board.push_back(sticker1);
board.push_back(sticker2);
}