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