From 41eaaaee31f1601126afd7616570e4b512142519 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 8 Apr 2025 13:58:54 -0400 Subject: [PATCH] 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 --- apps/diameter_client/ServerConnection.cpp | 136 ++++++------- core/AmArg.cpp | 220 +++++++++------------- core/AmArg.h | 158 +++++++--------- core/jsonArg.cpp | 17 +- 4 files changed, 236 insertions(+), 295 deletions(-) diff --git a/apps/diameter_client/ServerConnection.cpp b/apps/diameter_client/ServerConnection.cpp index fe4c8d47..02d34783 100644 --- a/apps/diameter_client/ServerConnection.cpp +++ b/apps/diameter_client/ServerConnection.cpp @@ -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"); diff --git a/core/AmArg.cpp b/core/AmArg.cpp index 2514d246..ec0d3024 100644 --- a/core/AmArg.cpp +++ b/core/AmArg.cpp @@ -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& v) +AmArg::AmArg(std::map& v) : type(Undef) { assertStruct(); for (std::map::iterator it= v.begin();it!= v.end();it++) - (*v_struct)[it->first] = AmArg(it->second.c_str()); + (*std::get(value))[it->first] = AmArg(it->second.c_str()); } -AmArg::AmArg(std::map& v) +AmArg::AmArg(std::map& v) : type(Undef) { assertStruct(); for (std::map::iterator it= v.begin();it!= v.end();it++) - (*v_struct)[it->first] = it->second; + (*std::get(value))[it->first] = it->second; } AmArg::AmArg(vector& v) : type(Array) { assertArray(0); - for (vector::iterator it + for (vector::iterator it = v.begin(); it != v.end(); it++) { push(AmArg(it->c_str())); } } - -AmArg::AmArg(const vector& v ) + +AmArg::AmArg(const vector& v ) : type(Array) { assertArray(0); - for (vector::const_iterator it + for (vector::const_iterator it = v.begin(); it != v.end(); it++) { push(AmArg(*it)); } @@ -113,7 +83,7 @@ AmArg::AmArg(const vector& v ) AmArg::AmArg(const vector& v) : type(Array) { assertArray(0); - for (vector::const_iterator it + for (vector::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(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(value) = new ValueArray(); } else if (Array != type) { throw TypeMismatchException(); } - if (v_array->size() < s) - v_array->resize(s); + if (std::get(value)->size() < s) + std::get(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(value); } + else if(type == Struct) { delete std::get(value); } type = Undef; + value = std::monostate(); } void AmArg::push(const AmArg& a) { assertArray(); - v_array->push_back(a); + std::get(value)->push_back(a); } void AmArg::push(const string &key, const AmArg &val) { assertStruct(); - (*v_struct)[key] = val; + (*std::get(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(value)->front(); + std::get(value)->erase(std::get(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(value)->back(); + std::get(value)->erase(std::get(value)->end()); } void AmArg::pop_back() { assertArray(); if (!size()) return; - v_array->erase(v_array->end()); + std::get(value)->erase(std::get(value)->end()); } void AmArg::concat(const AmArg& a) { assertArray(); - if (a.getType() == Array) { + if (a.getType() == Array) { for (size_t i=0;ipush_back(a[i]); + std::get(value)->push_back(a[i]); } else { - v_array->push_back(a); + std::get(value)->push_back(a); } } size_t AmArg::size() const { if (Array == type) - return v_array->size(); + return std::get(value)->size(); if (Struct == type) - return v_struct->size(); + return std::get(value)->size(); throw TypeMismatchException(); } AmArg& AmArg::back() { - assertArray(); - if (!v_array->size()) + assertArray(); + if (!std::get(value)->size()) throw OutOfBoundsException(); - return (*v_array)[v_array->size()-1]; + return (*std::get(value))[std::get(value)->size()-1]; } AmArg& AmArg::back() const { assertArray(); - if (!v_array->size()) + if (!std::get(value)->size()) throw OutOfBoundsException(); - return (*v_array)[v_array->size()-1]; + return (*std::get(value))[std::get(value)->size()-1]; } AmArg& AmArg::get(size_t idx) { assertArray(); - if (idx >= v_array->size()) + if (idx >= std::get(value)->size()) throw OutOfBoundsException(); - - return (*v_array)[idx]; + + return (*std::get(value))[idx]; } AmArg& AmArg::get(size_t idx) const { assertArray(); - if (idx >= v_array->size()) + if (idx >= std::get(value)->size()) throw OutOfBoundsException(); - - return (*v_array)[idx]; + + return (*std::get(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(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(value)->size()) throw OutOfBoundsException(); - - return (*v_array)[idx]; + + return (*std::get(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(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(value)->size()) throw OutOfBoundsException(); - - return (*v_array)[idx]; + + return (*std::get(value))[idx]; } AmArg& AmArg::operator[](std::string key) { assertStruct(); - return (*v_struct)[key]; + return (*std::get(value))[key]; } AmArg& AmArg::operator[](std::string key) const { assertStruct(); - return (*v_struct)[key]; + return (*std::get(value))[key]; } AmArg& AmArg::operator[](const char* key) { assertStruct(); - return (*v_struct)[key]; + return (*std::get(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(value))[key]; +} + +bool AmArg::operator==(const char *val) const { + return type == CStr && std::get(value) == val; } bool AmArg::hasMember(const char* name) const { - return type == Struct && v_struct->find(name) != v_struct->end(); + return type == Struct && std::get(value)->find(name) != std::get(value)->end(); } bool AmArg::hasMember(const string& name) const { - return type == Struct && v_struct->find(name) != v_struct->end(); + return type == Struct && std::get(value)->find(name) != std::get(value)->end(); } std::vector AmArg::enumerateKeys() const { assertStruct(); std::vector res; - for (ValueStruct::iterator it = - v_struct->begin(); it != v_struct->end(); it++) + for (ValueStruct::iterator it = + std::get(value)->begin(); it != std::get(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(value)->begin(); } AmArg::ValueStruct::const_iterator AmArg::end() const { assertStruct(); - return v_struct->end(); + return std::get(value)->end(); } void AmArg::erase(const char* name) { assertStruct(); - v_struct->erase(name); + std::get(value)->erase(name); } void AmArg::erase(const std::string& name) { assertStruct(); - v_struct->erase(name); + std::get(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 AmArg::asArgBlobVector() const { - vector res; - for (size_t i=0;i AmArg::asArgBlobVector() const { + vector res; + for (size_t i=0;i"; case Blob: - s = "len) + ">"; + s = ""; return s; case Array: s = "["; diff --git a/core/AmArg.h b/core/AmArg.h index 28dd2b5b..6542eff1 100644 --- a/core/AmArg.h +++ b/core/AmArg.h @@ -39,6 +39,7 @@ using std::vector; using std::string; #include +#include #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 ValueArray; - typedef std::map ValueStruct; + typedef std::map 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 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(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& v); @@ -198,7 +186,7 @@ class AmArg AmArg(const vector& v); AmArg(std::map& v); AmArg(std::map& 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 asStringVector() const; - vector asIntVector() const; - vector asBoolVector() const; - vector asDoubleVector() const; - vector asAmObjectVector() const; - vector asArgBlobVector() const; + int asInt() const { return std::get(value); } + long int asLong() const { return std::get(value); } + long long asLongLong() const { return std::get(value); } + bool asBool() const { return std::get(value); } + double asDouble() const { return std::get(value); } + const char* asCStr() const { return std::get(value).c_str(); } + AmObject* asObject() const { return std::get(value); } + AmDynInvoke* asDynInv() const { return std::get(value); } + const ArgBlob& asBlob() const { return std::get(value); } + ValueStruct* asStruct() const { return std::get(value); } + + vector asStringVector() const; + vector asIntVector() const; + vector asBoolVector() const; + vector asDoubleVector() const; + vector asAmObjectVector() const; + vector 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); diff --git a/core/jsonArg.cpp b/core/jsonArg.cpp index fa8cf9c9..88ce7346 100644 --- a/core/jsonArg.cpp +++ b/core/jsonArg.cpp @@ -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; }