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