blob: 6d00bc1d39eba794b1ff71780971d6ee456e74ce [file] [log] [blame]
/**
* Copyright © 2021 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "modifier.hpp"
#include "json/manager.hpp"
#include <fmt/format.h>
#include <phosphor-logging/log.hpp>
using namespace phosphor::logging;
namespace phosphor::fan::control::json
{
/**
* @brief Variant visitor to return a value of the template type specified.
*/
template <typename T>
struct ToTypeVisitor
{
template <typename U>
T operator()(const U& t) const
{
if constexpr (std::is_arithmetic_v<U> && std::is_arithmetic_v<T>)
{
return static_cast<T>(t);
}
throw std::invalid_argument(
"Non arithmetic type used in ToTypeVisitor");
}
};
/**
* @brief Implements the minus operator to subtract two values.
*
* With strings values, A - B removes all occurrences of B in A.
* Throws if the type is a bool.
*/
struct MinusOperator : public Modifier::BaseOperator
{
PropertyVariantType operator()(double val) override
{
return val - std::visit(ToTypeVisitor<double>(), arg);
}
PropertyVariantType operator()(int32_t val) override
{
return val - std::visit(ToTypeVisitor<int32_t>(), arg);
}
PropertyVariantType operator()(int64_t val) override
{
return val - std::visit(ToTypeVisitor<int64_t>(), arg);
}
PropertyVariantType operator()(const std::string& val) override
{
// Remove all occurrences of arg from val.
auto value = val;
auto toRemove = std::get<std::string>(arg);
size_t pos;
while ((pos = value.find(toRemove)) != std::string::npos)
{
value.erase(pos, toRemove.size());
}
return value;
}
PropertyVariantType operator()(bool val) override
{
throw std::runtime_error{
"Bool not allowed as a 'minus' modifier value"};
}
MinusOperator(PropertyVariantType& arg) : arg(arg)
{}
PropertyVariantType arg;
};
Modifier::Modifier(const json& jsonObj)
{
setValue(jsonObj);
setOperator(jsonObj);
}
void Modifier::setValue(const json& jsonObj)
{
if (!jsonObj.contains("value"))
{
log<level::ERR>(
fmt::format("Modifier entry in JSON missing 'value': {}",
jsonObj.dump())
.c_str());
throw std::invalid_argument("Invalid modifier JSON");
}
const auto& object = jsonObj.at("value");
if (auto boolPtr = object.get_ptr<const bool*>())
{
_value = *boolPtr;
}
else if (auto intPtr = object.get_ptr<const int64_t*>())
{
_value = *intPtr;
}
else if (auto doublePtr = object.get_ptr<const double*>())
{
_value = *doublePtr;
}
else if (auto stringPtr = object.get_ptr<const std::string*>())
{
_value = *stringPtr;
}
else
{
log<level::ERR>(
fmt::format(
"Invalid JSON type for value property in modifer json: {}",
jsonObj.dump())
.c_str());
throw std::invalid_argument("Invalid modifier JSON");
}
}
void Modifier::setOperator(const json& jsonObj)
{
if (!jsonObj.contains("operator"))
{
log<level::ERR>(
fmt::format("Modifier entry in JSON missing 'operator': {}",
jsonObj.dump())
.c_str());
throw std::invalid_argument("Invalid modifier JSON");
}
auto op = jsonObj["operator"].get<std::string>();
if (op == "minus")
{
_operator = std::make_unique<MinusOperator>(_value);
}
else
{
log<level::ERR>(fmt::format("Invalid operator in the modifier JSON: {}",
jsonObj.dump())
.c_str());
throw std::invalid_argument("Invalid operator in the modifier JSON");
}
}
PropertyVariantType Modifier::doOp(const PropertyVariantType& val)
{
return std::visit(*_operator, val);
}
} // namespace phosphor::fan::control::json