1 /** 2 * Copyright © 2021 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "modifier.hpp" 18 19 #include "json/manager.hpp" 20 21 #include <fmt/format.h> 22 23 #include <phosphor-logging/log.hpp> 24 25 using namespace phosphor::logging; 26 27 namespace phosphor::fan::control::json 28 { 29 30 /** 31 * @brief Variant visitor to return a value of the template type specified. 32 */ 33 template <typename T> 34 struct ToTypeVisitor 35 { 36 template <typename U> 37 T operator()(const U& t) const 38 { 39 if constexpr (std::is_arithmetic_v<U> && std::is_arithmetic_v<T>) 40 { 41 return static_cast<T>(t); 42 } 43 throw std::invalid_argument( 44 "Non arithmetic type used in ToTypeVisitor"); 45 } 46 }; 47 48 /** 49 * @brief Implements the minus operator to subtract two values. 50 * 51 * With strings values, A - B removes all occurrences of B in A. 52 * Throws if the type is a bool. 53 */ 54 struct MinusOperator : public Modifier::BaseOperator 55 { 56 PropertyVariantType operator()(double val) override 57 { 58 return val - std::visit(ToTypeVisitor<double>(), arg); 59 } 60 61 PropertyVariantType operator()(int32_t val) override 62 { 63 return val - std::visit(ToTypeVisitor<int32_t>(), arg); 64 } 65 66 PropertyVariantType operator()(int64_t val) override 67 { 68 return val - std::visit(ToTypeVisitor<int64_t>(), arg); 69 } 70 71 PropertyVariantType operator()(const std::string& val) override 72 { 73 // Remove all occurrences of arg from val. 74 auto value = val; 75 auto toRemove = std::get<std::string>(arg); 76 size_t pos; 77 while ((pos = value.find(toRemove)) != std::string::npos) 78 { 79 value.erase(pos, toRemove.size()); 80 } 81 82 return value; 83 } 84 85 PropertyVariantType operator()(bool val) override 86 { 87 throw std::runtime_error{ 88 "Bool not allowed as a 'minus' modifier value"}; 89 } 90 91 MinusOperator(PropertyVariantType& arg) : arg(arg) 92 {} 93 94 PropertyVariantType arg; 95 }; 96 97 Modifier::Modifier(const json& jsonObj) 98 { 99 setValue(jsonObj); 100 setOperator(jsonObj); 101 } 102 103 void Modifier::setValue(const json& jsonObj) 104 { 105 if (!jsonObj.contains("value")) 106 { 107 log<level::ERR>( 108 fmt::format("Modifier entry in JSON missing 'value': {}", 109 jsonObj.dump()) 110 .c_str()); 111 throw std::invalid_argument("Invalid modifier JSON"); 112 } 113 114 const auto& object = jsonObj.at("value"); 115 if (auto boolPtr = object.get_ptr<const bool*>()) 116 { 117 _value = *boolPtr; 118 } 119 else if (auto intPtr = object.get_ptr<const int64_t*>()) 120 { 121 _value = *intPtr; 122 } 123 else if (auto doublePtr = object.get_ptr<const double*>()) 124 { 125 _value = *doublePtr; 126 } 127 else if (auto stringPtr = object.get_ptr<const std::string*>()) 128 { 129 _value = *stringPtr; 130 } 131 else 132 { 133 log<level::ERR>( 134 fmt::format( 135 "Invalid JSON type for value property in modifer json: {}", 136 jsonObj.dump()) 137 .c_str()); 138 throw std::invalid_argument("Invalid modifier JSON"); 139 } 140 } 141 142 void Modifier::setOperator(const json& jsonObj) 143 { 144 if (!jsonObj.contains("operator")) 145 { 146 log<level::ERR>( 147 fmt::format("Modifier entry in JSON missing 'operator': {}", 148 jsonObj.dump()) 149 .c_str()); 150 throw std::invalid_argument("Invalid modifier JSON"); 151 } 152 153 auto op = jsonObj["operator"].get<std::string>(); 154 155 if (op == "minus") 156 { 157 _operator = std::make_unique<MinusOperator>(_value); 158 } 159 else 160 { 161 log<level::ERR>(fmt::format("Invalid operator in the modifier JSON: {}", 162 jsonObj.dump()) 163 .c_str()); 164 throw std::invalid_argument("Invalid operator in the modifier JSON"); 165 } 166 } 167 168 PropertyVariantType Modifier::doOp(const PropertyVariantType& val) 169 { 170 return std::visit(*_operator, val); 171 } 172 173 } // namespace phosphor::fan::control::json 174