/*
* Copyright (c) 2015, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ElementHandle.h"
#include "ParameterAccessContext.h"
#include "BaseParameter.h"
#include "XmlParameterSerializingContext.h"
#include "Subsystem.h"
#include <assert.h>
#include "ParameterMgr.h"
#include <mutex>
using std::string;
using std::mutex;
using std::lock_guard;
/** @return 0 by default, ie for non overloaded types. */
template <class T>
static size_t getUserInputSize(const T & /*scalar*/)
{
return 0;
}
/** @return the vector's size. */
template <class T>
static size_t getUserInputSize(const std::vector<T> &vector)
{
return vector.size();
}
ElementHandle::ElementHandle(CConfigurableElement &element, CParameterMgr ¶meterMgr)
: mElement(element), mParameterMgr(parameterMgr)
{
}
string ElementHandle::getName() const
{
return mElement.getName();
}
size_t ElementHandle::getSize() const
{
return mElement.getFootPrint();
}
bool ElementHandle::isParameter() const
{
return mElement.isParameter();
}
string ElementHandle::getDescription() const
{
return mElement.getDescription();
}
// Parameter features
bool ElementHandle::isRogue() const
{
return mElement.isRogue();
}
bool ElementHandle::isArray() const
{
return getArrayLength() != 0;
}
size_t ElementHandle::getArrayLength() const
{
// Only instances can be arrays, SystemClass can not, nor subsystems
auto *instance = dynamic_cast<CInstanceConfigurableElement *>(&mElement);
if (instance == nullptr) {
return 0;
}
return instance->getArrayLength();
}
string ElementHandle::getPath() const
{
return mElement.getPath();
}
string ElementHandle::getKind() const
{
return mElement.getKind();
}
std::vector<ElementHandle> ElementHandle::getChildren()
{
size_t nbChildren = mElement.getNbChildren();
std::vector<ElementHandle> children;
children.reserve(nbChildren);
for (size_t childIndex = 0; childIndex < nbChildren; ++childIndex) {
auto *child = static_cast<CConfigurableElement *>(mElement.getChild(childIndex));
// Can not use emplace back as the constructor is private
children.push_back({*child, mParameterMgr});
}
return children;
}
bool ElementHandle::getMappingData(const string &strKey, string &strValue) const
{
const std::string *pStrValue;
// Seach for the key in self and ancestors
auto elements = mElement.getConfigurableElementContext();
for (auto *element : elements)
if (element->getMappingData(strKey, pStrValue)) {
strValue = *pStrValue;
return true;
}
return false;
}
bool ElementHandle::getStructureAsXML(std::string &xmlSettings, std::string &error) const
{
// Use default access context for structure export
CParameterAccessContext accessContext(error);
return mParameterMgr.exportElementToXMLString(
&mElement, mElement.getXmlElementName(),
CXmlParameterSerializingContext{accessContext, error}, xmlSettings);
}
template <class T>
struct isVector : std::false_type
{
};
template <class T>
struct isVector<std::vector<T>> : std::true_type
{
};
bool ElementHandle::getAsXML(std::string &xmlValue, std::string &error) const
{
std::string result;
if (not mParameterMgr.getSettingsAsXML(&mElement, result)) {
error = result;
return false;
}
xmlValue = result;
return true;
}
bool ElementHandle::setAsXML(const std::string &xmlValue, std::string &error)
{
return mParameterMgr.setSettingsAsXML(&mElement, xmlValue, error);
}
bool ElementHandle::getAsBytes(std::vector<uint8_t> &bytesValue, std::string & /*error*/) const
{
mParameterMgr.getSettingsAsBytes(mElement, bytesValue);
// Currently this operation can not fail.
// Nevertheless this is more a design than intrinsic property.
// Use the same error reporting pattern to avoid breaking the api in future
// release if an error need to be reported (and be consistent with all other getAs*).
return true;
}
bool ElementHandle::setAsBytes(const std::vector<uint8_t> &bytesValue, std::string &error)
{
return mParameterMgr.setSettingsAsBytes(mElement, bytesValue, error);
}
template <class T>
bool ElementHandle::setAs(const T value, string &error) const
{
if (not checkSetValidity(getUserInputSize(value), error)) {
return false;
}
// Safe downcast thanks to isParameter check in checkSetValidity
auto ¶meter = static_cast<CBaseParameter &>(mElement);
// When in tuning mode, silently skip "set" requests
if (mParameterMgr.tuningModeOn()) {
return true;
}
CParameterAccessContext parameterAccessContext(error, mParameterMgr.getParameterBlackboard());
// BaseParamere::access takes a non-const argument - therefore we need to
// copy the value
T copy = value;
// Ensure we're safe against blackboard foreign access
lock_guard<mutex> autoLock(mParameterMgr.getBlackboardMutex());
return parameter.access(copy, true, parameterAccessContext);
}
template <class T>
bool ElementHandle::getAs(T &value, string &error) const
{
if (not checkGetValidity(isVector<T>::value, error)) {
return false;
}
// Safe downcast thanks to isParameter check in checkGetValidity
auto ¶meter = static_cast<const CBaseParameter &>(mElement);
// Ensure we're safe against blackboard foreign access
lock_guard<mutex> autoLock(mParameterMgr.getBlackboardMutex());
CParameterAccessContext parameterAccessContext(error, mParameterMgr.getParameterBlackboard());
return parameter.access(value, false, parameterAccessContext);
}
// Boolean access
bool ElementHandle::setAsBoolean(bool value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsBoolean(bool &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::setAsBooleanArray(const std::vector<bool> &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsBooleanArray(std::vector<bool> &value, string &error) const
{
return getAs(value, error);
}
// Integer Access
bool ElementHandle::setAsInteger(uint32_t value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsInteger(uint32_t &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::setAsIntegerArray(const std::vector<uint32_t> &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsIntegerArray(std::vector<uint32_t> &value, string &error) const
{
return getAs(value, error);
}
// Signed Integer Access
bool ElementHandle::setAsSignedInteger(int32_t value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsSignedInteger(int32_t &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::setAsSignedIntegerArray(const std::vector<int32_t> &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsSignedIntegerArray(std::vector<int32_t> &value, string &error) const
{
return getAs(value, error);
}
// Double Access
bool ElementHandle::setAsDouble(double value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsDouble(double &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::setAsDoubleArray(const std::vector<double> &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsDoubleArray(std::vector<double> &value, string &error) const
{
return getAs(value, error);
}
// String Access
bool ElementHandle::setAsString(const string &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsString(string &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::setAsStringArray(const std::vector<string> &value, string &error)
{
return setAs(value, error);
}
bool ElementHandle::getAsStringArray(std::vector<string> &value, string &error) const
{
return getAs(value, error);
}
bool ElementHandle::checkGetValidity(bool asArray, string &error) const
{
if (not isParameter()) {
error = "Can not set element " + getPath() + " as it is not a parameter.";
return false;
}
if (asArray != isArray()) {
auto toStr = [](bool array) { return array ? "an array" : "a scalar"; };
error = "Can not get \"" + getPath() + "\" as " + toStr(asArray) + " because it is " +
toStr(isArray());
return false;
}
return true;
}
// Access validity
bool ElementHandle::checkSetValidity(size_t arrayLength, string &error) const
{
// Settings a parameter necessitates the right to get it
if (not checkGetValidity(arrayLength != 0, error)) {
return false;
}
if (!isRogue()) {
error = "Can not set parameter \"" + getPath() + "\" as it is not rogue.";
return false;
}
if (arrayLength && (arrayLength != getArrayLength())) {
using std::to_string;
error = "Array length mismatch for \"" + getPath() + "\", expected: " +
to_string(getArrayLength()) + ", got: " + to_string(arrayLength);
return false;
}
return true;
}