forked from npshub/mantid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TypedValidator.h
143 lines (136 loc) · 4.97 KB
/
TypedValidator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2012 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/IValidator.h"
#include <typeinfo>
namespace Mantid {
namespace Kernel {
/**
TypedValidator provides an layer on top of IValidator to ensure
that the template TYPE is extract from the boost::any instance
and passed down to the concrete validator instance. Most validators
will probably want to inherit from this rather than IValidator
directly.
A specialised type exists for std::shared_ptr types
*/
template <typename HeldType> class DLLExport TypedValidator : public IValidator {
protected:
/// Override this function to check the validity of the type
virtual std::string checkValidity(const HeldType &) const = 0;
private:
/**
* Attempts to extract the TYPE from the boost any object and calls
* the typed checkValidity member
* @returns An error message to display to users or an empty string on no
* error
*/
std::string check(const boost::any &value) const override {
try {
const HeldType *dataPtr = boost::any_cast<const HeldType *>(value);
return checkValidity(*dataPtr);
} catch (boost::bad_any_cast &) {
return "Value was not of expected type.";
}
}
};
/**
* Specialization for std::shared_ptr<T> types.
* boost::any_cast cannot convert between types, the type extracted must match
* the
* the stored type. In our case IValidator ensures that all items that inherit
* from
* DataItem are stored as a DataItem_sptr within the boost::any instance. Once
* extracted
* the DataItem can then be downcast to the Validator::TYPE.
* The advantage of this is that Validator types then don't have to match
* their types exactly.
*/
template <typename ElementType> class DLLExport TypedValidator<std::shared_ptr<ElementType>> : public IValidator {
/// Shared ptr type
using ElementType_sptr = std::shared_ptr<ElementType>;
protected:
/// Override this function to check the validity of the type
virtual std::string checkValidity(const ElementType_sptr &) const = 0;
private:
/**
* Attempts to extract the TYPE from the boost any object and if
* the type is a DataItem_sptr then it attempts to downcast the value to
* the concrete type sepcified by the validator
* @param value :: The values to verify
* @returns An error message to display to users or an empty string on no
* error
*/
std::string check(const boost::any &value) const override {
try {
const ElementType_sptr typedValue = extractValue(value);
return checkValidity(typedValue);
} catch (std::invalid_argument &exc) {
return exc.what();
}
}
/**
* Extract the value type as the concrete type
* @param value :: The value
* @returns The concrete type
*/
ElementType_sptr extractValue(const boost::any &value) const {
// Despite the name and hash code being identical, operator== is returning false
// in Release mode
// with clang and libc++. The simplest workaround is to compare hash codes.
#ifdef __clang__
if (value.type().hash_code() == m_dataitemTypeID.hash_code())
#else
if (value.type() == m_dataitemTypeID)
#endif
{
return extractFromDataItem(value);
} else {
return extractFromSharedPtr(value);
}
}
/**
* Extract the DataItem value type by trying to downcast to the concrete type
* @param value :: The value
* @returns The concrete type
*/
ElementType_sptr extractFromDataItem(const boost::any &value) const {
const DataItem_sptr data = boost::any_cast<DataItem_sptr>(value);
// First try and push it up to the type of the validator
ElementType_sptr typedValue = std::dynamic_pointer_cast<ElementType>(data);
if (!typedValue) {
throw std::invalid_argument("DataItem \"" + data->getName() + "\" is not of the expected type.");
}
return typedValue;
}
/**
* Extract the the shared_ptr value type
* @param value :: The value
* @returns The concrete type
*/
ElementType_sptr extractFromSharedPtr(const boost::any &value) const {
try {
return boost::any_cast<ElementType_sptr>(value);
} catch (boost::bad_any_cast &) {
throw std::invalid_argument("Value was not a shared_ptr type");
}
}
/// Typeid of DataItem_sptr
static const std::type_info &m_dataitemTypeID;
};
/// @cond
// This switch off an warning because oxygen could not figureout that this is a
// specialized type of the general one.
/** Intialize the DataItem_sptr typeinfo
*/
template <typename T>
const std::type_info &TypedValidator<std::shared_ptr<T>>::m_dataitemTypeID = typeid(std::shared_ptr<DataItem>);
} // namespace Kernel
/// @endcond
} // namespace Mantid