/** * @file * * @copyright * @verbatim Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. @endverbatim */ #include "map_target.h" #include #include "a_util/result/error_def.h" #include "legacy_error_macros.h" #include "map_configuration.h" namespace mapping { namespace oo { //define all needed error types and values locally _MAKE_RESULT(-5, ERR_INVALID_ARG) _MAKE_RESULT(-19, ERR_NOT_SUPPORTED) _MAKE_RESULT(-20, ERR_NOT_FOUND) _MAKE_RESULT(-40, ERR_INVALID_STATE) } } using namespace mapping::oo; MapTarget::MapTarget(MapConfiguration* pConfig) : _config(pConfig), _is_valid(true) { } MapTarget::MapTarget(MapConfiguration* pConfig, std::string name, std::string strType) : _config(pConfig), _is_valid(true) { _name = name; _type = strType; } MapTarget::MapTarget(const MapTarget& oOther) { _name = oOther._name; _type = oOther._type; _assignments = oOther._assignments; _sources = oOther._sources; _is_valid = oOther._is_valid; _config = oOther._config; for (MapTriggerList::const_iterator it = oOther._triggers.begin(); it != oOther._triggers.end(); ++it) { _triggers.push_back((*it)->clone()); } } MapTarget& MapTarget::operator=(const MapTarget& oOther) { MapTarget oCopy(oOther); oCopy.swap(*this); return *this; } MapTarget::~MapTarget() { for (MapTriggerList::iterator it = _triggers.begin(); it != _triggers.end(); ++it) { delete *it; } _triggers.clear(); } const std::string& MapTarget::getName() const { return _name; } const std::string& MapTarget::getType() const { return _type; } bool MapTarget::isValid() const { return _is_valid; } const MapAssignmentList& MapTarget::getAssignmentList() const { return _assignments; } a_util::result::Result MapTarget::addAssignment(const MapAssignment& oAssignment) { if(!_config) { return ERR_INVALID_STATE; } RETURN_IF_FAILED(_config->resetErrors()); if(!_is_valid) { _config->appendError(a_util::strings::format("Target Signal %s is not valid, cannot add any assignment", _name.c_str())); return ERR_INVALID_STATE; } RETURN_IF_FAILED(_config->checkAssignmentReferences(oAssignment)); RETURN_IF_FAILED(addAssignmentNoTypeCheck(oAssignment)); // Check new assignment with ddl const ddl::DDLComplex* pTargetStruct = _config->_ddl_ref->getStructByName(_type); // Target is valid, so the type is defined and can be dereferenced a_util::result::Result nRes = _config->checkAssignmentType(_name, *pTargetStruct, oAssignment); if(isOk(nRes)) { nRes = checkDoubleAssignments(); } // If assignment not consistent with DDL, remove assignment if(isFailed(nRes)) { removeAssignmentWithoutClear(oAssignment.getTo()); } return nRes; } a_util::result::Result MapTarget::removeAssignment(const std::string& strElementName) { if(!_config) { return ERR_INVALID_STATE; } _config->_errors.clear(); return removeAssignmentWithoutClear(strElementName); } a_util::result::Result MapTarget::addTrigger(MapTriggerBase* pTrigger) { if(!_config) { return ERR_INVALID_STATE; } RETURN_IF_FAILED(_config->resetErrors()); if(!_is_valid) { _config->appendError(a_util::strings::format("Target Signal %s is not valid, cannot add any assignment", _name.c_str())); return ERR_INVALID_STATE; } if(pTrigger->_config != _config) { _config->appendError(a_util::strings::format("Trigger refers to another configuration")); return ERR_INVALID_STATE; } RETURN_IF_FAILED(pTrigger->checkTriggerReferences()); RETURN_IF_FAILED(_config->checkTriggerType(pTrigger)); return addTriggerNoTypeCheck(pTrigger); } a_util::result::Result MapTarget::removeTrigger(MapTriggerBase* pTrigger) { if(!_config) { return ERR_INVALID_STATE; } _config->_errors.clear(); bool bIsRemoved = false; std::string strSource; for(MapTriggerList::iterator it = _triggers.begin(); it != _triggers.end(); it++) { if((*it)->isEqual(*pTrigger)) { strSource = (*it)->getSourceDependency(); _triggers.erase(it); bIsRemoved = true; break; } } if(!strSource.empty()) { bool bIsSourceUsed = false; for(MapAssignmentList::const_iterator it = _assignments.begin(); it != _assignments.end(); it++) { if(it->getSource() == strSource) { bIsSourceUsed = true; } } for(MapTriggerList::const_iterator it = _triggers.begin(); it != _triggers.end(); it++) { if((*it)->getSourceDependency() == strSource) { bIsSourceUsed = true; } } if(!bIsSourceUsed) { for (MapSourceNameList::iterator itSource = _sources.begin(); itSource != _sources.end(); ++itSource) { if (*itSource == strSource) { _sources.erase(itSource); break; } } } } if(bIsRemoved) { return a_util::result::SUCCESS; } return ERR_NOT_FOUND; } a_util::result::Result MapTarget::removeAssignmentWithoutClear(const std::string& strElementName) { bool bIsRemoved = false; std::string strSource; for(MapAssignmentList::iterator it = _assignments.begin(); it != _assignments.end(); it++) { if(it->getTo() == strElementName) { strSource = it->getSource(); _assignments.erase(it); bIsRemoved = true; break; } } if(!strSource.empty()) { bool isSourceUsed = false; for(MapAssignmentList::const_iterator it = _assignments.begin(); it != _assignments.end(); it++) { if(it->getSource() == strSource) { isSourceUsed = true; } } for(MapTriggerList::const_iterator it = _triggers.begin(); it != _triggers.end(); it++) { if((*it)->getSourceDependency() == strSource) { isSourceUsed = true; } } if(!isSourceUsed) { for (MapSourceNameList::iterator itSource = _sources.begin(); itSource != _sources.end(); ++itSource) { if (*itSource == strSource) { _sources.erase(itSource); break; } } } } if(bIsRemoved) { return a_util::result::SUCCESS; } return ERR_NOT_FOUND; } a_util::result::Result MapTarget::addAssignmentNoTypeCheck(const MapAssignment& oAssignment) { // Assignment is attributed to an element const std::string& strTo = oAssignment.getTo(); if(strTo.empty()) { _config->appendError(a_util::strings::format("Target element name is empty in '%s'", _name.c_str())); return ERR_INVALID_ARG; } for(MapAssignmentList::iterator itAssign = _assignments.begin(); itAssign != _assignments.end(); itAssign++) { // Is To already assigned if (itAssign->getTo() == strTo) { _config->appendError( a_util::strings::format("Target element '%s' is already assigned in '%s'", strTo.c_str(), getName().c_str())); return ERR_INVALID_ARG; } } // Assignment is a constant, a connection or a function if (oAssignment.getSource().empty() && oAssignment.getConstant().empty() && oAssignment.getFunction().empty()) { _config->appendError(a_util::strings::format("Missing , or attribute for to '%s' in '%s'", strTo.c_str(), _name.c_str())); return ERR_INVALID_ARG; } // The constant is numeric if (!oAssignment.getConstant().empty() && !a_util::strings::isDouble(oAssignment.getConstant())) { _config->appendError( a_util::strings::format("Empty or non-numeric constant for to '%s' in '%s'", strTo.c_str(), _name.c_str())); return ERR_INVALID_ARG; } // The trigger_counter function modulo is numeric if (!oAssignment.getModulo().empty()) { if (!a_util::strings::isInt64(oAssignment.getModulo()) || oAssignment.getModulo().find('-') != std::string::npos || oAssignment.getModulo().find('+') != std::string::npos || a_util::strings::toUInt64(oAssignment.getModulo()) == 0) { _config->appendError( a_util::strings::format("Non-integer or zero modulo in transmission_counter for to '%s' in '%s'", strTo.c_str(), _name.c_str())); return ERR_INVALID_ARG; } } _assignments.push_back(oAssignment); if (!oAssignment.getSource().empty()) { for (MapSourceList::const_iterator itSource = _config->getSourceList().begin(); itSource != _config->getSourceList().end(); ++itSource) { if (itSource->getName() == oAssignment.getSource()) { _sources.insert(itSource->getName()); break; } } } return a_util::result::SUCCESS; } a_util::result::Result MapTarget::addTriggerNoTypeCheck(MapTriggerBase* pTrigger) { _triggers.push_back(pTrigger); // append dependency to references sources std::string strSourceDep = pTrigger->getSourceDependency(); if (!strSourceDep.empty()) { for (MapSourceList::const_iterator itSource = _config->getSourceList().begin(); itSource != _config->getSourceList().end(); ++itSource) { if (itSource->getName() == strSourceDep) { _sources.insert(itSource->getName()); break; } } } return a_util::result::SUCCESS; } a_util::result::Result MapTarget::modifySourceName(const std::string& name, const std::string& strNewName) { _sources.erase(name); _sources.insert(strNewName); for(MapAssignmentList::iterator itAssign = _assignments.begin(); itAssign != _assignments.end(); itAssign++) { if(itAssign->_source == name) { itAssign->_source = strNewName; } } for(MapTriggerList::iterator itTrigger = _triggers.begin(); itTrigger != _triggers.end(); itTrigger++) { if((*itTrigger)->getSourceDependency() == name) { (*itTrigger)->setSourceDependency(strNewName); } } return a_util::result::SUCCESS; } const MapTriggerList& MapTarget::getTriggerList() const { return _triggers; } a_util::result::Result MapTarget::loadFromDOM(const a_util::xml::DOMElement& oTarget) { _sources.clear(); _assignments.clear(); _triggers.clear(); // parse attributes const a_util::xml::DOMAttributes mapAttrs = oTarget.getAttributes(); a_util::xml::DOMAttributes::const_iterator itName = mapAttrs.find("name"); if (itName == mapAttrs.end() || itName->second.empty()) { _config->appendError("Missing name attribute for a "); return ERR_INVALID_ARG; } _name = itName->second; a_util::strings::trim(_name); a_util::xml::DOMAttributes::const_iterator itType = mapAttrs.find("type"); if (itType == mapAttrs.end() || itType->second.empty()) { _config->appendError(a_util::strings::format("Missing type attribute for '%s'", itName->second.c_str())); return ERR_INVALID_ARG; } _type = itType->second; a_util::strings::trim(_type); // parse assignments and triggers const a_util::xml::DOMElementList lstElements = oTarget.getChildren(); a_util::result::Result nResult = a_util::result::SUCCESS; for (a_util::xml::DOMElementList::const_iterator it = lstElements.begin(); it != lstElements.end(); ++it) { const a_util::xml::DOMElement& oElem = *it; const std::string& name = oElem.getName(); if (name == "assignment") { MapAssignment oAssign; a_util::result::Result nRes = oAssign.loadFromDOM(oElem, _config->_errors); if(isOk(nRes)) { nRes = addAssignmentNoTypeCheck(oAssign); } if (isFailed(nRes)) { nResult = nRes; } } else if (name == "trigger") { MapTriggerBase* pTrigger = NULL; a_util::result::Result nRes = MapTriggerBase::createFromDOM(_config, oElem, pTrigger); if(isOk(nRes)) { nRes = addTriggerNoTypeCheck(pTrigger); } if (isFailed(nRes)) { nResult = nRes; } } else { _config->appendError(a_util::strings::format("Invalid element type in '%s': '%s'", itName->second.c_str(), name.c_str())); nResult = ERR_INVALID_ARG; } } return nResult; } a_util::result::Result MapTarget::writeToDOM(a_util::xml::DOMElement& oDOMElement) const { oDOMElement.setName("target"); oDOMElement.setAttribute("name", _name); oDOMElement.setAttribute("type", _type); for(MapAssignmentList::const_iterator itAssign = _assignments.begin(); itAssign != _assignments.end(); itAssign++) { a_util::xml::DOMElement oDOMAssign = oDOMElement.createChild("assignment"); itAssign->writeToDOM(oDOMAssign); } for(MapTriggerList::const_iterator itTrigger = _triggers.begin(); itTrigger != _triggers.end(); itTrigger++) { a_util::xml::DOMElement oDOMTrigger = oDOMElement.createChild("trigger"); (*itTrigger)->writeToDOM(oDOMTrigger); } return a_util::result::SUCCESS; } a_util::result::Result MapTarget::checkDoubleAssignments() { a_util::result::Result nRes = a_util::result::SUCCESS; std::set oAssignedElList; for(MapAssignmentList::iterator itAssign = _assignments.begin(); itAssign != _assignments.end(); itAssign++) { oAssignedElList.insert(itAssign->getTo()); } for(MapAssignmentList::iterator itAssign = _assignments.begin(); itAssign != _assignments.end(); itAssign++) { for(std::set::iterator itParent = oAssignedElList.begin(); itParent != oAssignedElList.end(); itParent++) { std::string strEl = itAssign->getTo(); if(strEl.find(*itParent) == 0) { size_t pos = 0; while ((pos = strEl.find(*itParent, pos)) != std::string::npos) { strEl.replace(pos, itParent->length(), std::string()); pos += 1; } if(strEl.find('.') == 0 ||strEl.find('[') == 0) { _config->appendError(a_util::strings::format( " to '%s' not possible because of to %s in '%s'", strEl.c_str(), itParent->c_str(), getName().c_str())); itAssign->_is_valid = false; nRes = ERR_NOT_SUPPORTED; } } } } return nRes; } void MapTarget::swap(MapTarget& oOther) { using std::swap; swap(_config, oOther._config); swap(_name, oOther._name); swap(_type, oOther._type); swap(_assignments, oOther._assignments); swap(_sources, oOther._sources); swap(_triggers, oOther._triggers); } const MapSourceNameList& MapTarget::getReferencedSources() const { return _sources; } bool mapping::oo::operator==(const MapTarget& a, const MapTarget& b) { if (a.getName() != b.getName() || a.getType() != b.getType()) { return false; } const MapAssignmentList& lstAssignA = a.getAssignmentList(); const MapAssignmentList& lstAssignB = b.getAssignmentList(); if (lstAssignA.size() != lstAssignB.size() || !std::equal(lstAssignA.begin(), lstAssignA.end(), lstAssignB.begin())) { return false; } const MapTriggerList& lstTriggerA = a.getTriggerList(); const MapTriggerList& lstTriggerB = b.getTriggerList(); if (lstTriggerA.size() != lstTriggerB.size()) { return false; } MapTriggerList::const_iterator itA = lstTriggerA.begin(); MapTriggerList::const_iterator itB = lstTriggerB.begin(); for (; itA != lstTriggerA.end() && itB != lstTriggerB.end(); ++itA, ++itB) { if (!(*itA)->isEqual(*(*itB))) { return false; } } return true; } a_util::result::Result MapTarget::setName(const std::string& strNewName) { if(!_config) { return ERR_INVALID_STATE; } RETURN_IF_FAILED(_config->resetErrors()); RETURN_IF_FAILED(_config->checkSignalName(strNewName)); _name = strNewName; return _config->checkMappingConsistency(); } a_util::result::Result MapTarget::setType(const std::string& strType) { if(!_config) { return ERR_INVALID_STATE; } RETURN_IF_FAILED(_config->resetErrors()); RETURN_IF_FAILED(_config->checkSignalType(strType)); _type = strType; return _config->checkDDLConsistency(); }