1 #ifndef _OptionValidators_h_
2 #define _OptionValidators_h_
3 
4 #include <boost/any.hpp>
5 #include <boost/lexical_cast.hpp>
6 
7 #include <cmath>
8 #include <memory>
9 #include <set>
10 #include <string>
11 #include <vector>
12 
13 
14 // these are needed by the StepValidator
15 namespace details {
16     template <typename T>
mod(T dividend,T divisor)17     inline T mod (T dividend, T divisor)
18     { return (dividend % divisor); }
19 
20     template <>
21     inline float mod<float>(float dividend, float divisor)
22     { return std::fmod(dividend, divisor); }
23 
24     template <>
25     inline double mod<double>(double dividend, double divisor)
26     { return std::fmod(dividend, divisor); }
27 
28     template <>
29     inline long double mod<long double>(long double dividend, long double divisor)
30     { return std::fmod(dividend, divisor); }
31 }
32 
33 /** base class for all OptionsDB validators. Simply provides the basic interface. */
34 struct ValidatorBase
35 {
~ValidatorBaseValidatorBase36     virtual ~ValidatorBase()
37     {}
38 
39     /** returns normally if \a str is a valid value, or throws otherwise */
40     virtual boost::any Validate(const std::string& str) const = 0;
41 
42     /** returns the string representation of \a value */
43     virtual std::string String(const boost::any& value) const = 0;
44 
45     /** returns a dynamically allocated copy of the object. */
46     virtual ValidatorBase *Clone() const = 0;
47 };
48 
49 /** determines if a string is a valid value for an OptionsDB option */
50 template <typename T>
51 struct Validator : public ValidatorBase
52 {
ValidateValidator53     boost::any Validate(const std::string& str) const override
54     { return boost::any(boost::lexical_cast<T>(str)); }
55 
StringValidator56     std::string String(const boost::any& value) const override
57     { return boost::lexical_cast<std::string>(boost::any_cast<T>(value)); }
58 
CloneValidator59     Validator *Clone() const override
60     { return new Validator<T>(); }
61 };
62 
63 FO_COMMON_API std::string ListToString(const std::vector<std::string>& input_list);
64 FO_COMMON_API std::vector<std::string> StringToList(const std::string& input_string);
65 
66 template <>
67 struct Validator<std::vector<std::string>> : public ValidatorBase
68 {
69     boost::any Validate(const std::string& str) const override
70     { return boost::any(StringToList(str)); }
71 
72     std::string String(const boost::any& value) const override
73     { return ListToString(boost::any_cast<std::vector<std::string>>(value)); }
74 
75     Validator *Clone() const override
76     { return new Validator<std::vector<std::string>>(); }
77 };
78 
79 /** a Validator that constrains the range of valid values */
80 template <typename T>
81 struct RangedValidator : public Validator<T>
82 {
83     RangedValidator(const T& min, const T& max) : m_min(min), m_max(max) {}
84 
85     boost::any Validate(const std::string& str) const override {
86         T val = boost::lexical_cast<T>(str);
87         if (val < m_min || val > m_max)
88             throw boost::bad_lexical_cast();
89         return boost::any(val);
90     }
91 
92     RangedValidator *Clone() const override
93     { return new RangedValidator<T>(m_min, m_max); }
94 
95     const T m_min;
96     const T m_max;
97 };
98 
99 /** a Validator that constrains valid values to certain step-values
100     (eg: 0, 25, 50, ...).  The steps are assumed to begin at the
101     validated type's default-constructed value, unless another origin
102     is specified. */
103 template <typename T>
104 struct StepValidator : public Validator<T>
105 {
106     StepValidator(const T& step, const T& origin = T()) : m_step_size(step), m_origin(origin) {}
107 
108     boost::any Validate(const std::string& str) const override {
109         T val = boost::lexical_cast<T>(str);
110         if (std::abs(details::mod((val - m_origin), m_step_size)) > std::numeric_limits<T>::epsilon())
111             throw boost::bad_lexical_cast();
112         return boost::any(val);
113     }
114 
115     StepValidator *Clone() const override
116     { return new StepValidator<T>(m_step_size, m_origin); }
117 
118     const T m_step_size;
119     const T m_origin;
120 };
121 
122 /** a Validator similar to a StepValidator, but that further constrains the valid values to be within a certain range (eg: [25, 50, ..., 200]). */
123 template <typename T>
124 struct RangedStepValidator : public Validator<T>
125 {
126 public:
127     RangedStepValidator(const T& step, const T& min, const T& max) : m_step_size(step), m_origin(T()), m_min(min), m_max(max) {}
128     RangedStepValidator(const T& step, const T& origin, const T& min, const T& max) : m_step_size (step), m_origin (origin), m_min (min), m_max (max) {}
129 
130     boost::any Validate(const std::string& str) const override {
131         T val = boost::lexical_cast<T>(str);
132         if ((val < m_min) || (val > m_max) ||
133             ((std::abs(details::mod<T>(val - m_origin, m_step_size)) > std::numeric_limits<T>::epsilon()) &&
134              (std::abs(m_step_size - details::mod<T>(val - m_origin, m_step_size)) > std::numeric_limits<T>::epsilon())))
135             throw boost::bad_lexical_cast();
136         return boost::any(val);
137     }
138 
139     RangedStepValidator *Clone() const override
140     { return new RangedStepValidator<T>(m_step_size, m_origin, m_min, m_max); }
141 
142     const T m_step_size;
143     const T m_origin;
144     const T m_min;
145     const T m_max;
146 };
147 
148 /// a Validator that specifies a finite number of valid values.
149 /** Probably won't work well with floating point types. */
150 template <typename T>
151 struct DiscreteValidator : public Validator<T>
152 {
153     DiscreteValidator(const T& single_value) :
154         m_values(&single_value, &single_value + 1)
155     { }
156 
157     DiscreteValidator(const std::set<T>& values) :
158         m_values(values)
159     { }
160 
161     template <typename iter>
162     DiscreteValidator(iter start, iter finish) :
163         m_values(start, finish)
164     { }
165 
166     template <size_t N>
167     DiscreteValidator(const T (&in)[N]) :
168         m_values(in, in + N)
169     { }
170 
171     boost::any Validate(const std::string& str) const override {
172         T val = boost::lexical_cast<T>(str);
173 
174         if (!m_values.count(val))
175             throw boost::bad_lexical_cast();
176 
177         return boost::any(val);
178     }
179 
180     DiscreteValidator* Clone() const override
181     { return new DiscreteValidator<T>(m_values); }
182 
183     /// Stores the list of vaild values.
184     const std::set<T> m_values;
185 };
186 
187 /// a Validator that performs a logical OR of two validators.
188 /** Stores and owns clones of the provided validators in std::unique_ptr.
189  *  Always calls m_validator_a->Validate(). Only calls m_validator_b->Validate()
190  *  if the first one throws. */
191 template <typename T>
192 struct OrValidator : public Validator<T>
193 {
194     OrValidator(const Validator<T>& validator_a,
195                 const Validator<T>& validator_b) :
196         m_validator_a(validator_a.Clone()),
197         m_validator_b(validator_b.Clone())
198     { }
199 
200     boost::any Validate(const std::string& str) const override {
201         boost::any result;
202 
203         try {
204             result = m_validator_a->Validate(str);
205         } catch (boost::bad_lexical_cast&) {
206             result = m_validator_b->Validate(str);
207         }
208 
209         return result;
210     }
211 
212     OrValidator* Clone() const override
213     { return new OrValidator<T>(*m_validator_a.get(), *m_validator_b.get()); }
214 
215     const std::unique_ptr<Validator<T>> m_validator_a;
216     const std::unique_ptr<Validator<T>> m_validator_b;
217 };
218 
219 #endif // _OptionValidators_h_
220