Mantid
Loading...
Searching...
No Matches
PropertyWithValueJSON.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
13#include <json/value.h>
14#include <map>
15
16using Json::Value;
17
18namespace Mantid::Kernel {
19
20namespace {
21
22// A pointer to a member function for doing the Json::Value->C++ type conversion
23// Used only for type deduction in the FromJson constructor
24template <typename T> using ValueAsTypeMemFn = T (Json::Value::*)() const;
25
26// A non-templated outer struct that can be stored in a container without
27// requiring a pointer. The implementation follows the concept-model idiom
28// of storing the templated type using type erasure. Creating an object
29// of this type uses the type passed to the constructor to infer the
30// template parameter type. This template type is then used to call
31// the appropriate ToCpp conversion function defined in the header when
32// createProperty is called.
33struct FromJson {
34 template <typename T> explicit FromJson(ValueAsTypeMemFn<T> /*unused*/) : m_self{std::make_unique<ModelT<T>>()} {}
35
36 std::unique_ptr<Property> createProperty(const std::string &name, const Json::Value &value, bool createArray) const {
37 if (createArray)
38 return m_self->arrayValueProperty(name, value);
39 else
40 return m_self->singleValueProperty(name, value);
41 }
42
43private:
44 struct ConceptT {
45 virtual ~ConceptT() = default;
46 virtual std::unique_ptr<Property> singleValueProperty(const std::string &name, const Json::Value &value) const = 0;
47 virtual std::unique_ptr<Property> arrayValueProperty(const std::string &name, const Json::Value &value) const = 0;
48 };
49
50 template <typename T> struct ModelT : ConceptT {
51 std::unique_ptr<Property> singleValueProperty(const std::string &name,
52 const Json::Value &value) const override final {
53 using ToCppT = pwvjdetail::ToCpp<T>;
54 return std::make_unique<PropertyWithValue<T>>(name, ToCppT()(value));
55 }
56
57 std::unique_ptr<Property> arrayValueProperty(const std::string &name,
58 const Json::Value &value) const override final {
59 using ToCppVectorT = pwvjdetail::ToCpp<std::vector<T>>;
60 return std::make_unique<ArrayProperty<T>>(name, ToCppVectorT()(value));
61 }
62 };
63 std::unique_ptr<ConceptT> m_self;
64};
65
66// Define a lookup mapping Json::ValueTypes to a FromJson able to
67// create a PropertyWithValue object from that type
68using FromJsonConverters = std::map<Json::ValueType, FromJson>;
69
70// Returns (and creates on first call) the map of Json::ValueType to
71// FromJson for converting a JsonValue to a Property object
72const FromJsonConverters &converters() {
73 static FromJsonConverters converters;
74 if (converters.empty()) {
75 // Build a map of Json types to FromJson converters of the appropriate type
76 converters.insert(std::make_pair(Json::booleanValue, FromJson(&Json::Value::asBool)));
77 converters.insert(std::make_pair(Json::intValue, FromJson(&Json::Value::asInt)));
78 converters.insert(std::make_pair(Json::realValue, FromJson(&Json::Value::asDouble)));
79 converters.insert(std::make_pair(Json::stringValue, FromJson(&Json::Value::asString)));
80 }
81 return converters;
82}
83
94std::unique_ptr<Property> createSingleTypeProperty(const std::string &name, const Json::Value &value) {
95 const auto isArray = value.isArray();
96 FromJsonConverters::const_iterator conversionFnIter;
97 // For an array use the first element as the type checker and the rest must
98 // be convertible
99 if (isArray)
100 conversionFnIter = converters().find(value[0].type());
101 else
102 conversionFnIter = converters().find(value.type());
103
104 if (conversionFnIter == converters().end()) {
105 throw std::invalid_argument("Cannot create property with name " + name +
106 ". Unable to find converter "
107 "for Json::ValueType to C++ "
108 "type");
109 }
110 return conversionFnIter->second.createProperty(name, value, value.isArray());
111}
112
119std::unique_ptr<Property> createKeyValueProperty(const std::string &name, const Json::Value &keyValues) {
120 return std::make_unique<PropertyManagerProperty>(name, createPropertyManager(keyValues));
121}
122
123} // namespace
124
131PropertyManager_sptr createPropertyManager(const Json::Value &keyValues) {
132 auto propMgr = std::make_shared<PropertyManager>();
133 auto members = keyValues.getMemberNames();
134 for (const auto &key : members) {
135 const auto &value = keyValues[key];
136 if (value.isObject())
137 propMgr->declareProperty(createKeyValueProperty(key, value));
138 else
139 propMgr->declareProperty(createSingleTypeProperty(key, value));
140 }
141 return propMgr;
142}
143
152std::unique_ptr<Property> decodeAsProperty(const std::string &name, const Json::Value &value) {
153 if (value.isNull()) {
154 throw std::invalid_argument("decodeAsProperty(): Found null Json value.");
155 }
156
157 if (!value.isObject()) {
158 return createSingleTypeProperty(name, value);
159 } else {
160 return createKeyValueProperty(name, value);
161 }
162}
163
164} // namespace Mantid::Kernel
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
std::unique_ptr< ConceptT > m_self
MANTID_KERNEL_DLL std::unique_ptr< Property > decodeAsProperty(const std::string &name, const Json::Value &value)
Attempt to create a Property of the most appropriate type from a string name and Json value object.
MANTID_KERNEL_DLL PropertyManager_sptr createPropertyManager(const Json::Value &keyValues)
Attempt to create a PropertyManager from the Json::Value.
std::shared_ptr< PropertyManager > PropertyManager_sptr
Typedef for a shared pointer to a PropertyManager.
STL namespace.