MT#62181 AmArg: refactor as std::variant

This doesn't yet do much in terms of memory management as it still uses
pointers for arrays and structs, but it does move management of strings
and blobs into the variant. Further refactoring will bring the full
benefits.

Add specialised == operator to avoid implicit conversions to temporary
AmArg.

Includes white space cleanups.

Change-Id: I1e4bce6b96c2187294044f9f2a30fa7013912139
mr13.4
Richard Fuchs 1 year ago
parent a8b96bac1a
commit 41eaaaee31

@ -45,7 +45,7 @@
#define CHECK_TIMEOUT_USECS 500000 // 0.5ms
#define CHECK_TIMEOUT_INTERVAL (CHECK_TIMEOUT_USECS / CONN_WAIT_USECS)
// #define EXTRA_DEBUG
// #define EXTRA_DEBUG
#define CONNECT_CEA_REPLY_TIMEOUT 2 // seconds
#define RETRY_CONNECTION_INTERVAL 2 // seconds
@ -53,9 +53,9 @@
// after syserror, wait 30 secs for retry
#define RETRY_CONNECTION_SYSERROR 30 // seconds
DiameterServerConnection::DiameterServerConnection()
: in_use(false), dia_conn(0)
{
DiameterServerConnection::DiameterServerConnection()
: in_use(false), dia_conn(0)
{
memset(&rb, 0, sizeof(rd_buf_t));
h2h = random();
e2e = (time(NULL) & 0xFFF << 20) | (random() % 0xFFFFF);
@ -64,9 +64,9 @@ DiameterServerConnection::DiameterServerConnection()
void DiameterServerConnection::terminate(bool tls_shutdown) {
if (dia_conn) {
if (tls_shutdown)
if (tls_shutdown)
tcp_tls_shutdown(dia_conn);
tcp_close_connection(dia_conn);
tcp_destroy_connection(dia_conn);
dia_conn = NULL;
@ -105,7 +105,7 @@ void ServerConnection::process(AmEvent* ev) {
req_map_mut.unlock();
}
ServerConnection::ServerConnection()
ServerConnection::ServerConnection()
: server_port(-1), open(false),
AmEventQueue(this), request_timeout(3000),
timeout_check_cntr(0)
@ -117,11 +117,11 @@ ServerConnection::~ServerConnection() {
conn.terminate();
}
int ServerConnection::init(const string& _server_name,
int ServerConnection::init(const string& _server_name,
int _server_port,
const string& _ca_file,
const string& _cert_file,
const string& _origin_host,
const string& _origin_host,
const string& _origin_realm,
const string& _origin_ip,
AAAApplicationId _app_id,
@ -147,7 +147,7 @@ int ServerConnection::init(const string& _server_name,
struct in_addr inp;
if (inet_aton(origin_ip.c_str(), &inp) == 0) {
ERROR("origin_ip %s could not be decoded.\n",
ERROR("origin_ip %s could not be decoded.\n",
origin_ip.c_str());
} else {
origin_ip_address[2] = inp.s_addr & 0xFF;
@ -173,7 +173,7 @@ void ServerConnection::openConnection() {
conn.dia_conn = tcp_create_connection(server_name.c_str(), server_port,
ca_file.c_str(), cert_file.c_str());
if (!conn.dia_conn) {
ERROR("establishing connection to %s\n",
ERROR("establishing connection to %s\n",
server_name.c_str());
setRetryConnectLater();
return;
@ -188,10 +188,10 @@ void ServerConnection::openConnection() {
setRetryConnectLater();
return;
}
if (addOrigin(cer)
|| addDataAVP(cer, AVP_Host_IP_Address, origin_ip_address, sizeof(origin_ip_address))
|| addDataAVP(cer, AVP_Vendor_Id, (char*)&vendorID, sizeof(vendorID))
|| addDataAVP(cer, AVP_Supported_Vendor_Id, (char*)&vendorID, sizeof(vendorID))
if (addOrigin(cer)
|| addDataAVP(cer, AVP_Host_IP_Address, origin_ip_address, sizeof(origin_ip_address))
|| addDataAVP(cer, AVP_Vendor_Id, (char*)&vendorID, sizeof(vendorID))
|| addDataAVP(cer, AVP_Supported_Vendor_Id, (char*)&vendorID, sizeof(vendorID))
|| addStringAVP(cer, AVP_Product_Name, product_name)) {
ERROR("openConnection(): adding AVPs failed\n");
conn.terminate();
@ -201,7 +201,7 @@ void ServerConnection::openConnection() {
// supported applications
AAA_AVP* vs_appid;
if( (vs_appid=AAACreateAVP(AVP_Vendor_Specific_Application_Id, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, 0,
if( (vs_appid=AAACreateAVP(AVP_Vendor_Specific_Application_Id, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, 0,
0, AVP_DONT_FREE_DATA)) == 0) {
ERROR( M_NAME":openConnection(): creating AVP failed."
" (no more free memory!)\n");
@ -211,9 +211,9 @@ void ServerConnection::openConnection() {
}
// feels like c coding...
if (addGroupedAVP(vs_appid, AVP_Auth_Application_Id,
if (addGroupedAVP(vs_appid, AVP_Auth_Application_Id,
(char*)&app_id, sizeof(app_id)) ||
addGroupedAVP(vs_appid, AVP_Vendor_Id,
addGroupedAVP(vs_appid, AVP_Vendor_Id,
(char*)&vendorID, sizeof(vendorID)) ||
(AAAAddAVPToMessage(cer, vs_appid, 0) != AAA_ERR_SUCCESS)
) {
@ -224,18 +224,18 @@ void ServerConnection::openConnection() {
return;
}
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
AAAPrintMessage(cer);
#endif
conn.setIDs(cer);
if(AAABuildMsgBuffer(cer) != AAA_ERR_SUCCESS) {
ERROR( " openConnection(): message buffer not created\n");
AAAFreeMessage(&cer);
return;
}
int ret = tcp_send(conn.dia_conn, cer->buf.s, cer->buf.len);
if (ret) {
ERROR( "openConnection(): could not send message\n");
@ -244,14 +244,14 @@ void ServerConnection::openConnection() {
AAAFreeMessage(&cer);
return;
}
AAAFreeMessage(&cer);
unsigned int cea_receive_cnt = 3;
while (true) {
int res = tcp_recv_msg(conn.dia_conn, &conn.rb,
CONNECT_CEA_REPLY_TIMEOUT, 0);
if (res <= 0) {
if (!res) {
ERROR( " openConnection(): did not receive response (CEA).\n");
@ -262,9 +262,9 @@ void ServerConnection::openConnection() {
setRetryConnectLater();
return;
}
/* obtain the structure corresponding to the message */
AAAMessage* cea = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);
AAAMessage* cea = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);
if(!cea) {
ERROR( " openConnection(): could not decipher response (CEA).\n");
conn.terminate();
@ -273,7 +273,7 @@ void ServerConnection::openConnection() {
}
if (cea->commandCode == AAA_CC_CEA) {
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
AAAPrintMessage(cea);
#endif
AAAFreeMessage(&cea);
@ -289,7 +289,7 @@ void ServerConnection::openConnection() {
return;
}
}
DBG("Connection opened.\n");
open = true;
}
@ -300,35 +300,35 @@ AAAMessage* ServerConnection::ReqEvent2AAAMessage(DiameterRequestEvent* re) {
ERROR("creating new request message.\n");
return NULL;
}
for (int i=re->val.size()-1;i >= 0; i--) {
//[int avp_id, int flags, int vendor, int len, blob data]
AmArg& row = re->val.get(i);
int avp_id = row.get(0).asInt();
int flags = row.get(1).asInt();
int vendor = row.get(2).asInt();
ArgBlob* data = row.get(3).asBlob();
const ArgBlob& data = row.get(3).asBlob();
#ifdef EXTRA_DEBUG
DBG("adding avp id %d, flags %d, vendor %d\n", avp_id, flags, vendor);
#endif
#endif
if (!data->len) {
if (!data.len) {
#ifdef EXTRA_DEBUG
DBG("skipping empty AVP id %d\n", avp_id);
#endif
#endif
continue;
}
AAA_AVP *avp;
if( (avp=AAACreateAVP(avp_id, (AAA_AVPFlag)flags, vendor, (const char*)data->data,
data->len, AVP_DUPLICATE_DATA)) == 0) {
if( (avp=AAACreateAVP(avp_id, (AAA_AVPFlag)flags, vendor, (const char*)data.data,
data.len, AVP_DUPLICATE_DATA)) == 0) {
ERROR( M_NAME ": addDataAVP() no more free memory!\n");
continue;
}
if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) {
ERROR( M_NAME ": addDataAVP(): AVP not added!\n");
continue;
@ -339,12 +339,12 @@ AAAMessage* ServerConnection::ReqEvent2AAAMessage(DiameterRequestEvent* re) {
// add origin host and origin realm
int ServerConnection::addOrigin(AAAMessage* msg) {
return addStringAVP(msg, AVP_Origin_Host, origin_host, true) ||
return addStringAVP(msg, AVP_Origin_Host, origin_host, true) ||
addStringAVP(msg, AVP_Origin_Realm, origin_realm, true);
}
int ServerConnection::addStringAVP(AAAMessage* msg, AAA_AVPCode avp_code, string& val,
int ServerConnection::addStringAVP(AAAMessage* msg, AAA_AVPCode avp_code, string& val,
bool attail) {
AAA_AVP *avp;
if( (avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val.c_str(),
@ -385,11 +385,11 @@ int ServerConnection::addDataAVP(AAAMessage* msg, AAA_AVPCode avp_code, char* va
}
// add a new group member AVP
int ServerConnection::addGroupedAVP(AAA_AVP *avp, AAA_AVPCode avp_code,
int ServerConnection::addGroupedAVP(AAA_AVP *avp, AAA_AVPCode avp_code,
char* val, unsigned int len) {
AAA_AVP *m_avp;
if( (m_avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val,
if( (m_avp=AAACreateAVP(avp_code, (AAA_AVPFlag)AAA_AVP_FLAG_NONE, 0, val,
len, AVP_DUPLICATE_DATA)) == 0) {
ERROR( M_NAME":addGroupedAVP(): no more free memory!\n");
return -1;
@ -398,7 +398,7 @@ int ServerConnection::addGroupedAVP(AAA_AVP *avp, AAA_AVPCode avp_code,
return 0;
}
// send request and get response
// send request and get response
int ServerConnection::sendRequest(AAAMessage* req, unsigned int& exe) {
if (addOrigin(req)) {
return AAA_ERROR_MESSAGE;
@ -410,7 +410,7 @@ int ServerConnection::sendRequest(AAAMessage* req, unsigned int& exe) {
ERROR( " sendRequest(): message buffer not created\n");
return AAA_ERROR_MESSAGE;
}
int ret = tcp_send(conn.dia_conn, req->buf.s, req->buf.len);
if (ret) {
ERROR( " sendRequest(): could not send message\n");
@ -437,7 +437,7 @@ int ServerConnection::handleRequest(AAAMessage* req) {
}
AAAMessageSetReply(reply);
if (addOrigin(reply) || addResultCodeAVP(reply, AAA_SUCCESS)) {
AAAFreeMessage(&reply);
return AAA_ERROR_MESSAGE;
@ -451,7 +451,7 @@ int ServerConnection::handleRequest(AAAMessage* req) {
AAAFreeMessage(&reply);
return AAA_ERROR_MESSAGE;
}
DBG("sending Device-Watchdog-Answer...\n");
int ret = tcp_send(conn.dia_conn, reply->buf.s, reply->buf.len);
if (ret) {
@ -492,7 +492,7 @@ int ServerConnection::handleRequest(AAAMessage* req) {
AAAMessageSetReply(reply);
// always send success (causing retry of requests on
// always send success (causing retry of requests on
// different connection first, so race is unlikely)
if (addOrigin(reply) || addResultCodeAVP(reply, AAA_SUCCESS)) {
AAAFreeMessage(&reply);
@ -525,7 +525,7 @@ int ServerConnection::handleRequest(AAAMessage* req) {
}; break;
default: {
ERROR("ignoring unknown request with command code %i\n",
ERROR("ignoring unknown request with command code %i\n",
req->commandCode);
}; break;
}
@ -537,7 +537,7 @@ int ServerConnection::handleReply(AAAMessage* rep) {
unsigned int rep_id = rep->endtoendId;
int reply_code = AAAMessageGetReplyCode(rep);
DBG("received reply - id %d, reply code %d\n", rep_id, reply_code);
string sess_link = "";
req_map_mut.lock();
DReqMap::iterator it = req_map.find(rep_id);
@ -550,8 +550,8 @@ int ServerConnection::handleReply(AAAMessage* rep) {
req_map_mut.unlock();
if (!sess_link.empty()) {
DiameterReplyEvent* r_ev =
new DiameterReplyEvent((unsigned int)rep->commandCode, (unsigned int)rep->applicationId,
DiameterReplyEvent* r_ev =
new DiameterReplyEvent((unsigned int)rep->commandCode, (unsigned int)rep->applicationId,
AAAMessageAVPs2AmArg(rep));
if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
DBG("unhandled reply\n");
@ -563,14 +563,14 @@ int ServerConnection::handleReply(AAAMessage* rep) {
if ((reply_code == AAA_OUT_OF_SPACE)
|| reply_code >= AAA_PERMANENT_FAILURE_START) {
WARN("critical or permanent failure Diameter error reply"
" (code %d) received. Shutdown connection.\n",
" (code %d) received. Shutdown connection.\n",
reply_code);
shutdownConnection();
}
return 0;
}
AmArg ServerConnection::AAAMessageAVPs2AmArg(AAAMessage* rep) {
AmArg res;
for(AAA_AVP* avp=rep->avpList.head;avp;avp=avp->next) {
@ -624,23 +624,23 @@ void ServerConnection::receive() {
return;
/* obtain the structure corresponding to the message */
AAAMessage* msg = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);
AAAMessage* msg = AAATranslateMessage(conn.rb.buf, conn.rb.buf_len, 0);
if(!msg) {
ERROR( M_NAME "receive(): message structure not obtained from message.\n");
ERROR( M_NAME "receive(): message structure not obtained from message.\n");
closeConnection();
return;
}
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
AAAPrintMessage(msg);
#endif
if (is_req(msg))
if (is_req(msg))
handleRequest(msg);
else
else
handleReply(msg);
AAAFreeMessage(&msg);
AAAFreeMessage(&msg);
}
void ServerConnection::run() {
@ -649,7 +649,7 @@ void ServerConnection::run() {
if (!open) {
struct timeval now;
gettimeofday(&now, NULL);
if(timercmp(&now,&connect_ts,>)){
DBG("(re)trying to open the connection\n");
openConnection();
@ -666,7 +666,7 @@ void ServerConnection::run() {
}
void ServerConnection::checkTimeouts() {
if ((++timeout_check_cntr)%CHECK_TIMEOUT_INTERVAL)
if ((++timeout_check_cntr)%CHECK_TIMEOUT_INTERVAL)
return;
req_map_mut.lock();
@ -675,23 +675,23 @@ void ServerConnection::checkTimeouts() {
DBG("checking request timeout of %zd pending requests....\n",
req_map.size());
#endif
struct timeval now;
gettimeofday(&now, NULL);
for (DReqMap::iterator it =
for (DReqMap::iterator it =
req_map.begin();it != req_map.end();) {
struct timeval diff;
timersub(&now,&it->second.second,&diff);
// millisec
if (diff.tv_sec * 1000 + diff.tv_usec / 1000 > request_timeout) {
WARN("timeout for DIAMETER request '%u'\n", it->first);
WARN("timeout for DIAMETER request '%u'\n", it->first);
string& sess_link = it->second.first;
DBG("notify session '%s' of diameter request timeout\n",
DBG("notify session '%s' of diameter request timeout\n",
sess_link.c_str());
DiameterTimeoutEvent* r_ev =
DiameterTimeoutEvent* r_ev =
new DiameterTimeoutEvent(it->first);
if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
DBG("unhandled timout event.\n");
@ -718,7 +718,7 @@ void ServerConnection::shutdownConnection() {
for (DReqMap::iterator it = req_map.begin();
it != req_map.end();it++) {
string& sess_link = it->second.first;
DiameterTimeoutEvent* r_ev =
DiameterTimeoutEvent* r_ev =
new DiameterTimeoutEvent(it->first);
if (!AmSessionContainer::instance()->postEvent(sess_link, r_ev)) {
DBG("unhandled timout event.\n");

@ -46,65 +46,35 @@ const char* AmArg::t2str(int type) {
}
}
AmArg::AmArg(const AmArg& v)
{
type = Undef;
*this = v;
}
AmArg& AmArg::operator=(const AmArg& v) {
if (this != &v) {
invalidate();
type = v.type;
switch(type){
case Int: { v_int = v.v_int; } break;
case LongLong: { v_long = v.v_long; } break;
case Bool: { v_bool = v.v_bool; } break;
case Double: { v_double = v.v_double; } break;
case CStr: { v_cstr = strdup(v.v_cstr); } break;
case AObject:{ v_obj = v.v_obj; } break;
case ADynInv:{ v_inv = v.v_inv; } break;
case Array: { v_array = new ValueArray(*v.v_array); } break;
case Struct: { v_struct = new ValueStruct(*v.v_struct); } break;
case Blob: { v_blob = new ArgBlob(*v.v_blob); } break;
case Undef: break;
default: assert(0);
}
}
return *this;
}
AmArg::AmArg(std::map<std::string, std::string>& v)
AmArg::AmArg(std::map<std::string, std::string>& v)
: type(Undef) {
assertStruct();
for (std::map<std::string, std::string>::iterator it=
v.begin();it!= v.end();it++)
(*v_struct)[it->first] = AmArg(it->second.c_str());
(*std::get<ValueStruct*>(value))[it->first] = AmArg(it->second.c_str());
}
AmArg::AmArg(std::map<std::string, AmArg>& v)
AmArg::AmArg(std::map<std::string, AmArg>& v)
: type(Undef) {
assertStruct();
for (std::map<std::string, AmArg>::iterator it=
v.begin();it!= v.end();it++)
(*v_struct)[it->first] = it->second;
(*std::get<ValueStruct*>(value))[it->first] = it->second;
}
AmArg::AmArg(vector<std::string>& v)
: type(Array) {
assertArray(0);
for (vector<std::string>::iterator it
for (vector<std::string>::iterator it
= v.begin(); it != v.end(); it++) {
push(AmArg(it->c_str()));
}
}
AmArg::AmArg(const vector<int>& v )
AmArg::AmArg(const vector<int>& v )
: type(Array) {
assertArray(0);
for (vector<int>::const_iterator it
for (vector<int>::const_iterator it
= v.begin(); it != v.end(); it++) {
push(AmArg(*it));
}
@ -113,7 +83,7 @@ AmArg::AmArg(const vector<int>& v )
AmArg::AmArg(const vector<double>& v)
: type(Array) {
assertArray(0);
for (vector<double>::const_iterator it
for (vector<double>::const_iterator it
= v.begin(); it != v.end(); it++) {
push(AmArg(*it));
}
@ -124,9 +94,9 @@ void AmArg::assertArray() {
return;
if (Undef == type) {
type = Array;
v_array = new ValueArray();
std::get<ValueArray*>(value) = new ValueArray();
return;
}
}
throw TypeMismatchException();
}
@ -136,15 +106,15 @@ void AmArg::assertArray() const {
}
void AmArg::assertArray(size_t s) {
if (Undef == type) {
type = Array;
v_array = new ValueArray();
std::get<ValueArray*>(value) = new ValueArray();
} else if (Array != type) {
throw TypeMismatchException();
}
if (v_array->size() < s)
v_array->resize(s);
if (std::get<ValueArray*>(value)->size() < s)
std::get<ValueArray*>(value)->resize(s);
}
void AmArg::assertStruct() {
@ -152,9 +122,9 @@ void AmArg::assertStruct() {
return;
if (Undef == type) {
type = Struct;
v_struct = new ValueStruct();
value = new ValueStruct();
return;
}
}
throw TypeMismatchException();
}
@ -164,214 +134,196 @@ void AmArg::assertStruct() const {
}
void AmArg::invalidate() {
if(type == CStr) { free((void*)v_cstr); }
else if(type == Array) { delete v_array; }
else if(type == Struct) { delete v_struct; }
else if(type == Blob) { delete v_blob; }
if(type == Array) { delete std::get<ValueArray*>(value); }
else if(type == Struct) { delete std::get<ValueStruct*>(value); }
type = Undef;
value = std::monostate();
}
void AmArg::push(const AmArg& a) {
assertArray();
v_array->push_back(a);
std::get<ValueArray*>(value)->push_back(a);
}
void AmArg::push(const string &key, const AmArg &val) {
assertStruct();
(*v_struct)[key] = val;
(*std::get<ValueStruct*>(value))[key] = val;
}
void AmArg::pop(AmArg &a) {
assertArray();
if (!size()) {
if (a.getType() == AmArg::Undef)
if (a.getType() == AmArg::Undef)
return;
a = AmArg();
return;
}
a = v_array->front();
v_array->erase(v_array->begin());
a = std::get<ValueArray*>(value)->front();
std::get<ValueArray*>(value)->erase(std::get<ValueArray*>(value)->begin());
}
void AmArg::pop_back(AmArg &a) {
assertArray();
if (!size()) {
if (a.getType() == AmArg::Undef)
if (a.getType() == AmArg::Undef)
return;
a = AmArg();
return;
}
a = v_array->back();
v_array->erase(v_array->end());
a = std::get<ValueArray*>(value)->back();
std::get<ValueArray*>(value)->erase(std::get<ValueArray*>(value)->end());
}
void AmArg::pop_back() {
assertArray();
if (!size())
return;
v_array->erase(v_array->end());
std::get<ValueArray*>(value)->erase(std::get<ValueArray*>(value)->end());
}
void AmArg::concat(const AmArg& a) {
assertArray();
if (a.getType() == Array) {
if (a.getType() == Array) {
for (size_t i=0;i<a.size();i++)
v_array->push_back(a[i]);
std::get<ValueArray*>(value)->push_back(a[i]);
} else {
v_array->push_back(a);
std::get<ValueArray*>(value)->push_back(a);
}
}
size_t AmArg::size() const {
if (Array == type)
return v_array->size();
return std::get<ValueArray*>(value)->size();
if (Struct == type)
return v_struct->size();
return std::get<ValueStruct*>(value)->size();
throw TypeMismatchException();
}
AmArg& AmArg::back() {
assertArray();
if (!v_array->size())
assertArray();
if (!std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[v_array->size()-1];
return (*std::get<ValueArray*>(value))[std::get<ValueArray*>(value)->size()-1];
}
AmArg& AmArg::back() const {
assertArray();
if (!v_array->size())
if (!std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[v_array->size()-1];
return (*std::get<ValueArray*>(value))[std::get<ValueArray*>(value)->size()-1];
}
AmArg& AmArg::get(size_t idx) {
assertArray();
if (idx >= v_array->size())
if (idx >= std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[idx];
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::get(size_t idx) const {
assertArray();
if (idx >= v_array->size())
if (idx >= std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[idx];
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::operator[](size_t idx) {
assertArray(idx+1);
return (*v_array)[idx];
AmArg& AmArg::operator[](size_t idx) {
assertArray(idx+1);
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::operator[](size_t idx) const {
assertArray();
if (idx >= v_array->size())
AmArg& AmArg::operator[](size_t idx) const {
assertArray();
if (idx >= std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[idx];
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::operator[](int idx) {
AmArg& AmArg::operator[](int idx) {
if (idx<0)
throw OutOfBoundsException();
assertArray(idx+1);
return (*v_array)[idx];
assertArray(idx+1);
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::operator[](int idx) const {
AmArg& AmArg::operator[](int idx) const {
if (idx<0)
throw OutOfBoundsException();
assertArray();
if ((size_t)idx >= v_array->size())
assertArray();
if ((size_t)idx >= std::get<ValueArray*>(value)->size())
throw OutOfBoundsException();
return (*v_array)[idx];
return (*std::get<ValueArray*>(value))[idx];
}
AmArg& AmArg::operator[](std::string key) {
assertStruct();
return (*v_struct)[key];
return (*std::get<ValueStruct*>(value))[key];
}
AmArg& AmArg::operator[](std::string key) const {
assertStruct();
return (*v_struct)[key];
return (*std::get<ValueStruct*>(value))[key];
}
AmArg& AmArg::operator[](const char* key) {
assertStruct();
return (*v_struct)[key];
return (*std::get<ValueStruct*>(value))[key];
}
AmArg& AmArg::operator[](const char* key) const {
assertStruct();
return (*v_struct)[key];
}
bool operator==(const AmArg& lhs, const AmArg& rhs) {
if (lhs.type != rhs.type)
return false;
switch(lhs.type){
case AmArg::Int: { return lhs.v_int == rhs.v_int; } break;
case AmArg::LongLong: { return lhs.v_long == rhs.v_long; } break;
case AmArg::Bool: { return lhs.v_bool == rhs.v_bool; } break;
case AmArg::Double: { return lhs.v_double == rhs.v_double; } break;
case AmArg::CStr: { return !strcmp(lhs.v_cstr,rhs.v_cstr); } break;
case AmArg::AObject:{ return lhs.v_obj == rhs.v_obj; } break;
case AmArg::ADynInv:{ return lhs.v_inv == rhs.v_inv; } break;
case AmArg::Array: { return lhs.v_array == rhs.v_array; } break;
case AmArg::Struct: { return lhs.v_struct == rhs.v_struct; } break;
case AmArg::Blob: { return (lhs.v_blob->len == rhs.v_blob->len) &&
!memcmp(lhs.v_blob->data, rhs.v_blob->data, lhs.v_blob->len); } break;
case AmArg::Undef: return true;
default: assert(0);
}
return (*std::get<ValueStruct*>(value))[key];
}
bool AmArg::operator==(const char *val) const {
return type == CStr && std::get<std::string>(value) == val;
}
bool AmArg::hasMember(const char* name) const {
return type == Struct && v_struct->find(name) != v_struct->end();
return type == Struct && std::get<ValueStruct*>(value)->find(name) != std::get<ValueStruct*>(value)->end();
}
bool AmArg::hasMember(const string& name) const {
return type == Struct && v_struct->find(name) != v_struct->end();
return type == Struct && std::get<ValueStruct*>(value)->find(name) != std::get<ValueStruct*>(value)->end();
}
std::vector<std::string> AmArg::enumerateKeys() const {
assertStruct();
std::vector<std::string> res;
for (ValueStruct::iterator it =
v_struct->begin(); it != v_struct->end(); it++)
for (ValueStruct::iterator it =
std::get<ValueStruct*>(value)->begin(); it != std::get<ValueStruct*>(value)->end(); it++)
res.push_back(it->first);
return res;
}
AmArg::ValueStruct::const_iterator AmArg::begin() const {
assertStruct();
return v_struct->begin();
return std::get<ValueStruct*>(value)->begin();
}
AmArg::ValueStruct::const_iterator AmArg::end() const {
assertStruct();
return v_struct->end();
return std::get<ValueStruct*>(value)->end();
}
void AmArg::erase(const char* name) {
assertStruct();
v_struct->erase(name);
std::get<ValueStruct*>(value)->erase(name);
}
void AmArg::erase(const std::string& name) {
assertStruct();
v_struct->erase(name);
std::get<ValueStruct*>(value)->erase(name);
}
void AmArg::assertArrayFmt(const char* format) const {
@ -390,7 +342,7 @@ void AmArg::assertArrayFmt(const char* format) const {
case 'a': assertArgArray(get(i)); got+='a'; break;
case 'b': assertArgBlob(get(i)); got+='b'; break;
case 'u': assertArgStruct(get(i)); got+='u'; break;
default: got+='?'; ERROR("ignoring unknown format type '%c'\n",
default: got+='?'; ERROR("ignoring unknown format type '%c'\n",
format[i]); break;
}
}
@ -407,7 +359,7 @@ void AmArg::assertArrayFmt(const char* format) const {
for (size_t i=0;i<size();i++) \
res.push_back(get(i).getter()); \
return res; \
}
}
VECTOR_GETTER(string, asStringVector, asCStr)
VECTOR_GETTER(int, asIntVector, asInt)
VECTOR_GETTER(bool, asBoolVector, asBool)
@ -415,12 +367,12 @@ VECTOR_GETTER(double, asDoubleVector, asDouble)
VECTOR_GETTER(AmObject*, asAmObjectVector, asObject)
#undef VECTOR_GETTER
vector<ArgBlob> AmArg::asArgBlobVector() const {
vector<ArgBlob> res;
for (size_t i=0;i<size();i++)
res.push_back(*get(i).asBlob());
return res;
}
vector<ArgBlob> AmArg::asArgBlobVector() const {
vector<ArgBlob> res;
for (size_t i=0;i<size();i++)
res.push_back(get(i).asBlob());
return res;
}
void AmArg::clear() {
invalidate();
@ -446,7 +398,7 @@ string AmArg::print(const AmArg &a) {
case ADynInv:
return "<DynInv>";
case Blob:
s = "<Blob of size:" + int2str(a.asBlob()->len) + ">";
s = "<Blob of size:" + int2str(a.asBlob().len) + ">";
return s;
case Array:
s = "[";

@ -39,6 +39,7 @@ using std::vector;
using std::string;
#include <map>
#include <variant>
#include "log.h"
@ -49,14 +50,14 @@ class AmObject {
virtual ~AmObject() { }
};
struct ArgBlob {
struct ArgBlob {
void* data;
int len;
ArgBlob()
ArgBlob()
: data(NULL),len(0)
{
{
}
ArgBlob(const ArgBlob& a) {
@ -65,14 +66,14 @@ struct ArgBlob {
if (data)
memcpy(data, a.data, len);
}
ArgBlob(const void* _data, int _len) {
len = _len;
data = malloc(len);
if (data)
memcpy(data, _data, len);
}
~ArgBlob() { if (data) free(data); }
};
@ -95,7 +96,7 @@ class AmArg
AObject, // pointer to an object not owned by AmArg
ADynInv, // pointer to a AmDynInvoke (useful for call backs)
Blob,
Array,
Struct
};
@ -107,90 +108,77 @@ class AmArg
struct TypeMismatchException {
TypeMismatchException() { }
};
typedef std::vector<AmArg> ValueArray;
typedef std::map<std::string, AmArg> ValueStruct;
typedef std::map<std::string, AmArg> ValueStruct;
private:
// type
short type;
// value
union {
long int v_int;
long long int v_long;
bool v_bool;
double v_double;
const char* v_cstr;
AmObject* v_obj;
AmDynInvoke* v_inv;
ArgBlob* v_blob;
ValueArray* v_array;
ValueStruct* v_struct;
};
std::variant<std::monostate, long int, long long int, bool, double, std::string, AmObject*,
AmDynInvoke*, ArgBlob, ValueArray*, ValueStruct*> value;
void invalidate();
public:
AmArg()
: type(Undef)
AmArg()
: type(Undef)
{ }
AmArg(const AmArg& v);
AmArg(const AmArg& v) = default;
AmArg(const int& v)
: type(Int),
v_int(v)
value(static_cast<long>(v))
{ }
AmArg(const long int& v)
: type(Int),
v_int(v)
value(v)
{ }
AmArg(const long long int& v)
: type(LongLong),
v_long(v)
value(v)
{ }
AmArg(const bool& v)
: type(Bool),
v_bool(v)
value(v)
{ }
AmArg(const double& v)
: type(Double),
v_double(v)
value(v)
{ }
AmArg(const char* v)
: type(CStr)
{
v_cstr = strdup(v);
}
: type(CStr),
value(v)
{ }
AmArg(const string &v)
: type(CStr)
{
v_cstr = strdup(v.c_str());
}
AmArg(const ArgBlob v)
: type(Blob)
{
v_blob = new ArgBlob(v);
}
: type(CStr),
value(v)
{ }
AmArg(const ArgBlob& v)
: type(Blob),
value(v)
{ }
AmArg(AmObject* v)
: type(AObject),
v_obj(v)
{ }
AmArg(AmObject* v)
: type(AObject),
value(v)
{ }
AmArg(AmDynInvoke* v)
: type(ADynInv),
v_inv(v)
{ }
AmArg(AmDynInvoke* v)
: type(ADynInv),
value(v)
{ }
// convenience constructors
AmArg(vector<std::string>& v);
@ -198,7 +186,7 @@ class AmArg
AmArg(const vector<double>& v);
AmArg(std::map<std::string, std::string>& v);
AmArg(std::map<std::string, AmArg>& v);
~AmArg() { invalidate(); }
void assertArray();
@ -209,7 +197,7 @@ class AmArg
short getType() const { return type; }
AmArg& operator=(const AmArg& rhs);
AmArg& operator=(const AmArg& rhs) = default;
#define isArgUndef(a) (AmArg::Undef == a.getType())
#define isArgArray(a) (AmArg::Array == a.getType())
@ -227,7 +215,7 @@ class AmArg
do { \
ERROR("type mismatch: expected: %d; received: %d.\n", AmArg::exp, got.getType()); \
throw AmArg::TypeMismatchException(); \
} while (0)
} while (0)
#define assertArgArray(a) \
if (!isArgArray(a)) \
@ -263,26 +251,26 @@ class AmArg
void setBorrowedPointer(AmObject* v) {
invalidate();
type = AObject;
v_obj = v;
value = v;
}
int asInt() const { return (int)v_int; }
long int asLong() const { return v_int; }
long long asLongLong() const { return v_long; }
int asBool() const { return v_bool; }
double asDouble() const { return v_double; }
const char* asCStr() const { return v_cstr; }
AmObject* asObject() const { return v_obj; }
AmDynInvoke* asDynInv() const { return v_inv; }
ArgBlob* asBlob() const { return v_blob; }
ValueStruct* asStruct() const { return v_struct; }
vector<string> asStringVector() const;
vector<int> asIntVector() const;
vector<bool> asBoolVector() const;
vector<double> asDoubleVector() const;
vector<AmObject*> asAmObjectVector() const;
vector<ArgBlob> asArgBlobVector() const;
int asInt() const { return std::get<long>(value); }
long int asLong() const { return std::get<long>(value); }
long long asLongLong() const { return std::get<long long>(value); }
bool asBool() const { return std::get<bool>(value); }
double asDouble() const { return std::get<double>(value); }
const char* asCStr() const { return std::get<std::string>(value).c_str(); }
AmObject* asObject() const { return std::get<AmObject*>(value); }
AmDynInvoke* asDynInv() const { return std::get<AmDynInvoke*>(value); }
const ArgBlob& asBlob() const { return std::get<ArgBlob>(value); }
ValueStruct* asStruct() const { return std::get<ValueStruct*>(value); }
vector<string> asStringVector() const;
vector<int> asIntVector() const;
vector<bool> asBoolVector() const;
vector<double> asDoubleVector() const;
vector<AmObject*> asAmObjectVector() const;
vector<ArgBlob> asArgBlobVector() const;
// operations on arrays
void assertArray(size_t s);
@ -294,7 +282,7 @@ class AmArg
void pop_back();
void concat(const AmArg& a);
size_t size() const;
/** throws OutOfBoundsException if array too small */
@ -324,6 +312,8 @@ class AmArg
AmArg& operator[](const char* key);
AmArg& operator[](const char* key) const;
bool operator==(const char *) const;
/** Check for the existence of a struct member by name. */
bool hasMember(const std::string& name) const;
bool hasMember(const char* name) const;
@ -337,9 +327,9 @@ class AmArg
/** remove struct member */
void erase(const std::string& name);
/**
* throws exception if arg array does not conform to spec
* i - int
/**
* throws exception if arg array does not conform to spec
* i - int
* l - long long
* t - bool
* f - double
@ -355,7 +345,6 @@ class AmArg
void assertArrayFmt(const char* format) const;
void clear();
friend bool operator==(const AmArg& lhs, const AmArg& rhs);
friend bool json2arg(std::istream& input, AmArg& res);
@ -364,9 +353,6 @@ class AmArg
static const char* t2str(int type);
};
// equality
bool operator==(const AmArg& lhs, const AmArg& rhs);
const int arg2int(const AmArg &a);
string arg2str(const AmArg &a);

@ -243,18 +243,21 @@ bool json2arg(std::istream& input, AmArg& res) {
return true;
}
if (parse_float(input, &res.v_double)) {
res.type = AmArg::Double;
double d;
if (parse_float(input, &d)) {
res = d;
return true;
}
if (parse_number(input, &res.v_int)) {
res.type = AmArg::Int;
long l;
if (parse_number(input, &l)) {
res = l;
return true;
}
if (parse_bool(input, &res.v_bool)) {
res.type = AmArg::Bool;
bool b;
if (parse_bool(input, &b)) {
res = b;
return true;
}

Loading…
Cancel
Save