| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "na64util/exception.hh" | ||
| 2 | #include "na64util/str-fmt.hh" | ||
| 3 | |||
| 4 | #include <cstdio> | ||
| 5 | #include <limits> | ||
| 6 | #include <sstream> | ||
| 7 | #include <string> | ||
| 8 | #include <type_traits> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <typeinfo> | ||
| 11 | #include <cassert> | ||
| 12 | |||
| 13 | #include <unordered_set> | ||
| 14 | #include <yaml-cpp/exceptions.h> | ||
| 15 | #include <yaml-cpp/yaml.h> | ||
| 16 | |||
| 17 | namespace na64dp { | ||
| 18 | namespace errors { | ||
| 19 | |||
| 20 | /// Root exception class for all the PDef errors | ||
| 21 | class PDefError : public GenericRuntimeError { | ||
| 22 | public: | ||
| 23 | std::list<std::string> path; | ||
| 24 | public: | ||
| 25 | 39 | PDefError(const char * msg) : GenericRuntimeError(msg) {} | |
| 26 | }; | ||
| 27 | |||
| 28 | /// No item found in section by given key | ||
| 29 | class NoKeyInSection : public PDefError { | ||
| 30 | public: | ||
| 31 | const std::string key; | ||
| 32 | public: | ||
| 33 | ✗ | NoKeyInSection(const char * key_) | |
| 34 | ✗ | : PDefError("Item not found in section") | |
| 35 | ✗ | , key(key_) | |
| 36 | ✗ | {} | |
| 37 | }; | ||
| 38 | |||
| 39 | /// No item found in section by given key | ||
| 40 | class NoItemInArray : public PDefError { | ||
| 41 | public: | ||
| 42 | const ssize_t key; | ||
| 43 | public: | ||
| 44 | ✗ | NoItemInArray(ssize_t key_) | |
| 45 | ✗ | : PDefError("No item of this number in array") | |
| 46 | ✗ | , key(key_) | |
| 47 | ✗ | {} | |
| 48 | }; | ||
| 49 | |||
| 50 | /// Basic error thrown by validators | ||
| 51 | class InvalidParameter : public PDefError { | ||
| 52 | public: | ||
| 53 | 14 | InvalidParameter(const char * msg) : PDefError(msg) {} | |
| 54 | }; | ||
| 55 | |||
| 56 | ///\brief Requested type does not support the value | ||
| 57 | /// | ||
| 58 | /// Thrown when assignment (destination) type is not large enough to keep | ||
| 59 | /// the source value | ||
| 60 | class ParameterTypeOverflow : public InvalidParameter { | ||
| 61 | public: | ||
| 62 | ParameterTypeOverflow(const char * msg) : InvalidParameter(msg) {} | ||
| 63 | }; | ||
| 64 | |||
| 65 | /// Basic error thrown by validators if value has permitted type but | ||
| 66 | /// value is prohibited | ||
| 67 | class InvalidParameterValue : public InvalidParameter { | ||
| 68 | public: | ||
| 69 | 4 | InvalidParameterValue(const char * msg) : InvalidParameter(msg) {} | |
| 70 | }; | ||
| 71 | |||
| 72 | /// Thrown when bad parameter or parameter section or array name is provided | ||
| 73 | class InvalidParameterName : public InvalidParameter { | ||
| 74 | public: | ||
| 75 | ✗ | InvalidParameterName(const char * msg) : InvalidParameter(msg) {} | |
| 76 | }; | ||
| 77 | |||
| 78 | /// Type cast errors | ||
| 79 | class InvalidParameterType : public InvalidParameter { | ||
| 80 | public: | ||
| 81 | 9 | InvalidParameterType(const char * msg) : InvalidParameter(msg) {} | |
| 82 | }; | ||
| 83 | |||
| 84 | /// Parameter is not set, but its value requested in runtime context | ||
| 85 | class ParameterValueIsNotSet : public InvalidParameter { | ||
| 86 | public: | ||
| 87 | 1 | ParameterValueIsNotSet() : InvalidParameter("Parameter value is not set") {} | |
| 88 | }; | ||
| 89 | |||
| 90 | /// Thrown if path expression is invalid | ||
| 91 | class BadPath : public PDefError { | ||
| 92 | public: | ||
| 93 | std::string path; | ||
| 94 | size_t nChar; | ||
| 95 | 20 | BadPath(const char * msg, size_t nc) : PDefError(msg), nChar(nc) {} | |
| 96 | }; | ||
| 97 | |||
| 98 | /// Thrown in case of inconsistent parameter definition | ||
| 99 | class PDefInconsistency : public PDefError { | ||
| 100 | public: | ||
| 101 | 5 | PDefInconsistency(const char * msg) : PDefError(msg) {} | |
| 102 | }; | ||
| 103 | |||
| 104 | /// Thrown in case of re-definition already defined node | ||
| 105 | class NodeRedefinition : public PDefInconsistency { | ||
| 106 | public: | ||
| 107 | 5 | NodeRedefinition(const char * msg) : PDefInconsistency(msg) {} | |
| 108 | }; | ||
| 109 | |||
| 110 | /// Root exception class for all YAML-related errors | ||
| 111 | class GenericYAMLError : public PDefError { | ||
| 112 | public: | ||
| 113 | YAML::Exception origError; | ||
| 114 | public: | ||
| 115 | GenericYAMLError(const YAML::Exception & e, const char * msg) | ||
| 116 | : PDefError(msg) | ||
| 117 | , origError(e) | ||
| 118 | {} | ||
| 119 | }; | ||
| 120 | |||
| 121 | } // namespace ::na64dp::error | ||
| 122 | namespace util { | ||
| 123 | class Composer; // fwd | ||
| 124 | namespace pdef { | ||
| 125 | |||
| 126 | // | ||
| 127 | // Runtime parameters path | ||
| 128 | |||
| 129 | /// Returns true if given string can be used as parameter name (scalar, | ||
| 130 | /// section, array, etc) | ||
| 131 | bool validate_parameter_name(const char * nm); | ||
| 132 | |||
| 133 | /// Single path token entry | ||
| 134 | struct PathToken { | ||
| 135 | enum { | ||
| 136 | kUnknown = 0x0, | ||
| 137 | |||
| 138 | kAnyStrKey = 0x2, | ||
| 139 | kStrKey = kAnyStrKey | 0x1, | ||
| 140 | |||
| 141 | kAnyIndex = 0x4, | ||
| 142 | kIntKey = kAnyIndex | 0x1, | ||
| 143 | } type; | ||
| 144 | union { | ||
| 145 | const char * stringKey; | ||
| 146 | ssize_t index; | ||
| 147 | } pl; | ||
| 148 | |||
| 149 | 44 | PathToken() : type(kUnknown), pl{nullptr} {} | |
| 150 | 36 | PathToken(const char * ptr) : type(kStrKey), pl{ptr} {} | |
| 151 | 10 | PathToken(ssize_t i) : type(kIntKey), pl{.index=i} {} | |
| 152 | }; | ||
| 153 | |||
| 154 | ///\brief Path to parameter | ||
| 155 | /// Modifies provided string to obtain representation of parameter path | ||
| 156 | /// | ||
| 157 | /// Path examples: | ||
| 158 | /// "" | ||
| 159 | /// "one" | ||
| 160 | /// "one.two" | ||
| 161 | /// "one[0].two.three" | ||
| 162 | /// "one.*.three" | ||
| 163 | /// "one.foo*.bar[34]" | ||
| 164 | /// "one[*].two" | ||
| 165 | class Path : public std::vector<PathToken> { | ||
| 166 | private: | ||
| 167 | /// Null-delimited list of tokens of size `_strBufLen`, may be not allocated | ||
| 168 | char * _strBuf; | ||
| 169 | /// Size of path string buffer | ||
| 170 | size_t _strBufLen; | ||
| 171 | public: | ||
| 172 | Path(const char * strexpr=nullptr); | ||
| 173 | 3 | Path(const std::string & cppStr) : Path(cppStr.c_str()) {} | |
| 174 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 5 taken 1 times.
|
1 | Path(const Path & orig) : Path(orig.to_string().c_str()) {} |
| 175 | ~Path(); | ||
| 176 | |||
| 177 | Path & operator=(const Path &); | ||
| 178 | |||
| 179 | std::string to_string() const; | ||
| 180 | |||
| 181 | operator std::string() const { return to_string(); } | ||
| 182 | }; | ||
| 183 | |||
| 184 | // | ||
| 185 | // Scalars | ||
| 186 | |||
| 187 | /// Parameter definition base class | ||
| 188 | struct BasePDef { | ||
| 189 | virtual void set(const YAML::Node &) = 0; | ||
| 190 | 8 | virtual ~BasePDef() {} | |
| 191 | }; | ||
| 192 | |||
| 193 | /// Common base for scalar parameters | ||
| 194 | class BaseScalar : public BasePDef { | ||
| 195 | private: | ||
| 196 | /// RO attr, C++ RTTI type | ||
| 197 | const std::type_info & _typeInfo; | ||
| 198 | protected: | ||
| 199 | bool _isSet; | ||
| 200 | public: | ||
| 201 | 18 | BaseScalar(const std::type_info & ti) : _typeInfo(ti), _isSet(false) {} | |
| 202 | /// Returns ref to C++ RTTI type | ||
| 203 | const std::type_info & type_info() const { return _typeInfo; } | ||
| 204 | |||
| 205 | 17 | bool is_set() const { return _isSet; } | |
| 206 | |||
| 207 | template<typename T> void set_as_of_type(const T &); | ||
| 208 | template<typename T> T get_as_of_type() const; | ||
| 209 | }; | ||
| 210 | |||
| 211 | template<typename T> | ||
| 212 | class Scalar : public BaseScalar { | ||
| 213 | public: | ||
| 214 | struct iValidator { | ||
| 215 | /// Shall throw exception if parameter is not valid | ||
| 216 | virtual void validate(const T &) const = 0; | ||
| 217 | }; | ||
| 218 | protected: | ||
| 219 | std::shared_ptr<iValidator> _validator; | ||
| 220 | T _value; | ||
| 221 | public: | ||
| 222 | 36 | Scalar() : BaseScalar(typeid(T)) | |
| 223 | 36 | , _validator(nullptr) | |
| 224 | 36 | {} | |
| 225 | |||
| 226 | 3 | void set_validator(std::shared_ptr<iValidator> vv) { | |
| 227 | 3 | _validator = vv; | |
| 228 | 3 | } | |
| 229 | |||
| 230 | 22 | void set(const T & v) { | |
| 231 | 22 | _value = v; | |
| 232 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 4 times.
|
22 | if(_validator) _validator->validate(_value); |
| 233 | 14 | _isSet = true; | |
| 234 | 14 | } | |
| 235 | |||
| 236 | ✗ | void set(const YAML::Node & yamlNode) { | |
| 237 | ✗ | _value = yamlNode.as<T>(); | |
| 238 | ✗ | if(_validator) _validator->validate(_value); | |
| 239 | ✗ | _isSet = true; | |
| 240 | } | ||
| 241 | |||
| 242 | 5 | T get() const { | |
| 243 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
|
5 | if(!is_set()) throw errors::ParameterValueIsNotSet(); |
| 244 | 4 | return _value; | |
| 245 | } | ||
| 246 | }; // class Scalar | ||
| 247 | |||
| 248 | // TODO: this getters now throw `std::bad_cast` in case of type mismatch. It is | ||
| 249 | // possible, however, to involve a table of permitted conversions to perform | ||
| 250 | // implicit static casts | ||
| 251 | |||
| 252 | template<typename T> void | ||
| 253 | BaseScalar::set_as_of_type(const T & v) { | ||
| 254 | dynamic_cast<Scalar<T>>(*this).set(v); | ||
| 255 | } | ||
| 256 | |||
| 257 | template<typename T> T | ||
| 258 | BaseScalar::get_as_of_type() const { | ||
| 259 | return dynamic_cast<Scalar<T>>(*this).get(); | ||
| 260 | } | ||
| 261 | |||
| 262 | // | ||
| 263 | // Basic validators for scalar parameters | ||
| 264 | |||
| 265 | template<typename T> | ||
| 266 | struct RangeValidator : public Scalar<T>::iValidator { | ||
| 267 | T left, right; | ||
| 268 | 9 | RangeValidator() : left( std::numeric_limits<T>::min()) | |
| 269 | 3 | , right(std::numeric_limits<T>::max()) | |
| 270 | 3 | {} | |
| 271 | 7 | void validate(const T & v) const override { | |
| 272 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
|
10 | if(v >= left && v <= right) return; |
| 273 |
1/1✓ Branch 1 taken 4 times.
|
4 | std::ostringstream oss; |
| 274 | 4 | if( left != std::numeric_limits<T>::min() | |
| 275 |
6/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
|
4 | && right != std::numeric_limits<T>::max() |
| 276 | ) { | ||
| 277 |
1/1✓ Branch 1 taken 2 times.
|
2 | oss << "value " << v |
| 278 |
6/6✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 13 taken 2 times.
✓ Branch 16 taken 2 times.
|
2 | << " is out of range [" << left << ", " << right << "]"; |
| 279 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | } else if( right != std::numeric_limits<T>::max() ) { |
| 280 |
1/1✓ Branch 1 taken 1 times.
|
1 | oss << "value " << v |
| 281 |
3/3✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
|
1 | << " should be less than or equal to " << right; |
| 282 | } else { | ||
| 283 |
1/1✓ Branch 1 taken 1 times.
|
1 | oss << "value " << v |
| 284 |
3/3✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 7 taken 1 times.
|
1 | << " should be greater than or equal to " << left; |
| 285 | } | ||
| 286 |
1/1✓ Branch 2 taken 4 times.
|
4 | throw errors::InvalidParameterValue(oss.str().c_str()); |
| 287 | 4 | } | |
| 288 | }; | ||
| 289 | |||
| 290 | template<typename T> | ||
| 291 | struct SetValidator : public Scalar<T>::iValidator { | ||
| 292 | std::unordered_set<T> permittedValues; | ||
| 293 | SetValidator() {} | ||
| 294 | |||
| 295 | void validate(const T & v) const override { | ||
| 296 | auto it = permittedValues.find(v); | ||
| 297 | if(it != permittedValues.end()) return; | ||
| 298 | std::ostringstream oss; | ||
| 299 | if(permittedValues.size() > 6) { // TODO: configurable | ||
| 300 | oss << "Value \"" << v << "\" is not recognized."; | ||
| 301 | } else { | ||
| 302 | for(const auto & pv : permittedValues) { | ||
| 303 | std::set<std::string> sorted( permittedValues.begin() | ||
| 304 | , permittedValues.end() | ||
| 305 | ); | ||
| 306 | oss << "Value \"" << v << "\" is not one of the permitted options: " | ||
| 307 | << str_join(sorted.begin(), sorted.end()); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | throw errors::InvalidParameterValue(oss.str().c_str()); | ||
| 311 | } | ||
| 312 | }; | ||
| 313 | |||
| 314 | // TODO: regex validator | ||
| 315 | // TODO: non-zero (single prohibited value) validator | ||
| 316 | |||
| 317 | // | ||
| 318 | // Parameter tree node | ||
| 319 | |||
| 320 | /// Node of parameter definition tree | ||
| 321 | class Node { | ||
| 322 | public: | ||
| 323 | /// This node description (public RW) | ||
| 324 | std::string description; | ||
| 325 | /// Node-section type | ||
| 326 | typedef std::unordered_map<std::string, std::shared_ptr<Node>> Section; | ||
| 327 | /// Node-array type; can have homogeneous topology | ||
| 328 | struct Array : public std::vector<std::shared_ptr<Node>> { | ||
| 329 | std::shared_ptr<Node> topology; ///< desired topology for array, can be null | ||
| 330 | }; | ||
| 331 | private: | ||
| 332 | // this is not exposed to parent scope, should be steered by this class only | ||
| 333 | /// This node type | ||
| 334 | enum { | ||
| 335 | kUnset = 0, ///< empty node, no value type defined | ||
| 336 | kScalar, ///< node contains some kind of scalar value | ||
| 337 | kArray, ///< list/array node | ||
| 338 | kSection, ///< (sub-)section node | ||
| 339 | kUnion, ///< union type | ||
| 340 | kCustom ///< node with custom parameter | ||
| 341 | } _type; | ||
| 342 | /// Node payload | ||
| 343 | union { | ||
| 344 | util::pdef::BasePDef * parameterPtr; | ||
| 345 | Section * section; | ||
| 346 | Array * array; | ||
| 347 | } _pl; | ||
| 348 | public: | ||
| 349 | 48 | Node() : _type(kUnset) | |
| 350 | 24 | , _pl{nullptr} | |
| 351 | 24 | {} | |
| 352 | |||
| 353 | 7 | bool is_unset() const { return _type == kUnset; } | |
| 354 | 15 | bool is_section() const { return _type == kSection; } | |
| 355 | 8 | bool is_scalar() const { return _type == kScalar; } | |
| 356 | 9 | bool is_array() const { return _type == kArray; } | |
| 357 | bool is_union() const { return _type == kUnion; } | ||
| 358 | 4 | bool is_custom() const { return _type == kCustom; } | |
| 359 | |||
| 360 | const char * node_type_name() const; | ||
| 361 | |||
| 362 | ///\brief Marks unset node as scalar of given type | ||
| 363 | /// | ||
| 364 | ///\throws errors::NodeRedefinition if node already has type | ||
| 365 | template<typename T> | ||
| 366 | 36 | pdef::Scalar<T> & set_scalar() { | |
| 367 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
|
36 | if(_type != kUnset) throw errors::NodeRedefinition("Node type has been set already"); |
| 368 | 30 | _type = kScalar; | |
| 369 | 30 | _pl.parameterPtr = new Scalar<T>(); | |
| 370 | 30 | return *static_cast<pdef::Scalar<T>*>(_pl.parameterPtr); | |
| 371 | } | ||
| 372 | ///\brief Marks node as section node | ||
| 373 | /// | ||
| 374 | ///\throws errors::NodeRedefinition if node already has type | ||
| 375 | Section & set_section(); | ||
| 376 | ///\brief Marks node as section node | ||
| 377 | /// | ||
| 378 | ///\throws errors::NodeRedefinition if node already has type | ||
| 379 | Array & set_array(); | ||
| 380 | // TODO: ? | ||
| 381 | //\brief Marks node as union node | ||
| 382 | // | ||
| 383 | //\throws errors::NodeRedefinition if node already has type | ||
| 384 | //Union & set_union(); | ||
| 385 | |||
| 386 | BaseScalar & as_scalar(); | ||
| 387 | const BaseScalar & as_scalar() const; | ||
| 388 | 5 | template<typename T> Scalar<T> & as_scalar_of_type() { | |
| 389 | 5 | auto & bs = as_scalar(); | |
| 390 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | return dynamic_cast<Scalar<T>&>(bs); |
| 391 | } | ||
| 392 | 8 | template<typename T> const Scalar<T> & as_scalar_of_type() const { | |
| 393 | 8 | auto & bs = as_scalar(); | |
| 394 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | return dynamic_cast<const Scalar<T>&>(bs); |
| 395 | } | ||
| 396 | |||
| 397 | Section & as_section(); | ||
| 398 | const Section & as_section() const; | ||
| 399 | |||
| 400 | Array & as_array(); | ||
| 401 | const Array & as_array() const; | ||
| 402 | |||
| 403 | // section getter shortcuts | ||
| 404 | Node & operator[](const std::string &); | ||
| 405 | const Node & operator[](const std::string &) const; | ||
| 406 | bool has(const std::string &) const; | ||
| 407 | |||
| 408 | // array getter shortcuts | ||
| 409 | Node & operator[](ssize_t); | ||
| 410 | const Node & operator[](ssize_t) const; | ||
| 411 | bool has(ssize_t) const; | ||
| 412 | }; | ||
| 413 | |||
| 414 | #if 1 | ||
| 415 | class Composer { | ||
| 416 | private: | ||
| 417 | struct NodeEntry { | ||
| 418 | Node & node; | ||
| 419 | std::string name; | ||
| 420 | size_t index; | ||
| 421 | std::shared_ptr<Node> _lastNode; | ||
| 422 | }; | ||
| 423 | std::vector<NodeEntry> _stack; | ||
| 424 | protected: | ||
| 425 | void _assure_array(); | ||
| 426 | void _assure_section(); | ||
| 427 | public: | ||
| 428 | Composer() = delete; | ||
| 429 | Composer(Node & node); | ||
| 430 | |||
| 431 | /// Defines required scalar named parameter (attribute), with name and | ||
| 432 | /// optional description | ||
| 433 | template<typename T> | ||
| 434 | 8 | Composer & p( const char * name | |
| 435 | , const char * description=nullptr | ||
| 436 | ) { | ||
| 437 |
1/1✓ Branch 1 taken 4 times.
|
8 | _assure_section(); |
| 438 |
2/3✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
8 | if(!validate_parameter_name(name)) |
| 439 | ✗ | throw errors::InvalidParameterName("Invalid parameter name."); | |
| 440 | |||
| 441 |
1/1✓ Branch 1 taken 4 times.
|
8 | auto nodePtr = std::make_shared<Node>(); |
| 442 |
1/1✓ Branch 2 taken 4 times.
|
8 | nodePtr->set_scalar<T>(); |
| 443 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | if(description) |
| 444 |
1/1✓ Branch 2 taken 4 times.
|
8 | nodePtr->description = description; |
| 445 |
2/2✓ Branch 2 taken 4 times.
✓ Branch 5 taken 4 times.
|
8 | _stack.back().node.as_section().emplace(name, nodePtr); |
| 446 | 8 | _stack.back()._lastNode = nodePtr; | |
| 447 | 8 | return *this; | |
| 448 | 8 | } | |
| 449 | |||
| 450 | /// Defines required scalar named parameter (attribute), with name, | ||
| 451 | /// validator and optional description | ||
| 452 | template<typename T> | ||
| 453 | Composer & p( const char * name | ||
| 454 | , std::shared_ptr<typename Scalar<T>::iValidator> & validator | ||
| 455 | , const char * description=nullptr | ||
| 456 | ) { | ||
| 457 | _assure_section(); | ||
| 458 | if(!validate_parameter_name(name)) | ||
| 459 | throw errors::InvalidParameterName("Invalid parameter name."); | ||
| 460 | |||
| 461 | auto nodePtr = std::make_shared<Node>(); | ||
| 462 | nodePtr->set_scalar<T>().set_validator(validator); | ||
| 463 | if(description) | ||
| 464 | nodePtr->description = description; | ||
| 465 | _stack.back().node.as_section().emplace(name, nodePtr); | ||
| 466 | _stack.back()._lastNode = nodePtr; | ||
| 467 | return *this; | ||
| 468 | } | ||
| 469 | |||
| 470 | /// Defines (optional) scalar named parameter (attribute), with name, | ||
| 471 | /// default value and optional description | ||
| 472 | template<typename T> | ||
| 473 | 6 | Composer & p( const char * name | |
| 474 | , T dftVal | ||
| 475 | , const char * description=nullptr | ||
| 476 | ) { | ||
| 477 |
1/1✓ Branch 1 taken 3 times.
|
6 | _assure_section(); |
| 478 |
2/3✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
6 | if(!validate_parameter_name(name)) |
| 479 | ✗ | throw errors::InvalidParameterName("Invalid parameter name."); | |
| 480 | |||
| 481 |
1/1✓ Branch 1 taken 3 times.
|
6 | auto nodePtr = std::make_shared<Node>(); |
| 482 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
|
6 | nodePtr->set_scalar<T>().set(dftVal); |
| 483 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | if(description) |
| 484 |
1/1✓ Branch 2 taken 3 times.
|
6 | nodePtr->description = description; |
| 485 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 5 taken 3 times.
|
6 | _stack.back().node.as_section().emplace(name, nodePtr); |
| 486 | 6 | _stack.back()._lastNode = nodePtr; | |
| 487 | 6 | return *this; | |
| 488 | 6 | } | |
| 489 | |||
| 490 | /// Defines (optional) scalar named parameter (attribute), with name, | ||
| 491 | /// validator, default value and optional description | ||
| 492 | template<typename T> | ||
| 493 | Composer & p( const char * name | ||
| 494 | , std::shared_ptr<typename Scalar<T>::iValidator> & validator | ||
| 495 | , T dftVal | ||
| 496 | , const char * description=nullptr | ||
| 497 | ) { | ||
| 498 | _assure_section(); | ||
| 499 | if(!validate_parameter_name(name)) | ||
| 500 | throw errors::InvalidParameterName("Invalid parameter name."); | ||
| 501 | |||
| 502 | auto nodePtr = std::make_shared<Node>(); | ||
| 503 | auto & s = nodePtr->set_scalar<T>(); | ||
| 504 | s.set_validator(validator); | ||
| 505 | s.set(dftVal); | ||
| 506 | if(description) | ||
| 507 | nodePtr->description = description; | ||
| 508 | _stack.back().node.as_section().emplace(name, nodePtr); | ||
| 509 | _stack.back()._lastNode = nodePtr; | ||
| 510 | return *this; | ||
| 511 | } | ||
| 512 | |||
| 513 | /// Defines required scalar parameter element, with optional description | ||
| 514 | template<typename T> | ||
| 515 | 4 | Composer & el( const char * description=nullptr ) { | |
| 516 |
1/1✓ Branch 1 taken 2 times.
|
4 | _assure_array(); |
| 517 |
1/1✓ Branch 1 taken 2 times.
|
4 | auto nodePtr = std::make_shared<Node>(); |
| 518 |
1/1✓ Branch 2 taken 2 times.
|
4 | nodePtr->set_scalar<T>(); |
| 519 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | if(description) |
| 520 |
1/1✓ Branch 2 taken 2 times.
|
4 | nodePtr->description = description; |
| 521 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
|
4 | _stack.back().node.as_array().push_back(nodePtr); |
| 522 | 4 | _stack.back()._lastNode = nodePtr; | |
| 523 | 4 | return *this; | |
| 524 | 4 | } | |
| 525 | |||
| 526 | /// Defines attribute sub-node (section or array) | ||
| 527 | 1 | Composer & bgn_sub( const char * name | |
| 528 | , const char * description=nullptr | ||
| 529 | ) { | ||
| 530 |
1/1✓ Branch 1 taken 1 times.
|
1 | _assure_section(); |
| 531 |
2/3✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if(!validate_parameter_name(name)) |
| 532 | ✗ | throw errors::InvalidParameterName("Invalid subsection name."); | |
| 533 | |||
| 534 |
1/1✓ Branch 1 taken 1 times.
|
1 | auto nodePtr = std::make_shared<Node>(); |
| 535 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(description) |
| 536 |
1/1✓ Branch 2 taken 1 times.
|
1 | nodePtr->description = description; |
| 537 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
|
1 | _stack.back().node.as_section().emplace(name, nodePtr); |
| 538 | 1 | _stack.back()._lastNode = nodePtr; | |
| 539 |
2/3✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 10 not taken.
|
2 | _stack.push_back(NodeEntry{*nodePtr, name, 0}); |
| 540 | 1 | return *this; | |
| 541 | 1 | } | |
| 542 | |||
| 543 | /// Finalizes attribute sub-node (section or array) | ||
| 544 | 1 | Composer & end_sub( const char * name=nullptr ) { | |
| 545 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(name) { |
| 546 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(_stack.size() < 2) { |
| 547 | ✗ | throw errors::InvalidParameterName(format("No " | |
| 548 | " opened subsections to finalize \"%s\"" | ||
| 549 | ✗ | , name).c_str()); | |
| 550 | } | ||
| 551 | 1 | auto it = _stack.rbegin(); | |
| 552 |
3/4✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
1 | if(name != it->name) { |
| 553 | ✗ | throw errors::InvalidParameterName(format("Finilizing" | |
| 554 | " subsection \"%s\" while lates open is \"%s\"" | ||
| 555 | ✗ | , name, it->name.c_str() | |
| 556 | ✗ | ).c_str()); | |
| 557 | } | ||
| 558 | } | ||
| 559 | 1 | _stack.pop_back(); | |
| 560 | 1 | return *this; | |
| 561 | } | ||
| 562 | |||
| 563 | #if 0 | ||
| 564 | /// Defines required parameter with validator, name and description | ||
| 565 | template<typename T> | ||
| 566 | Composer & p( const char * name | ||
| 567 | , std::shared_ptr<typename pdef::Scalar<T>::iValidator> & validator | ||
| 568 | , const char * description=nullptr | ||
| 569 | ) { | ||
| 570 | if(_lastNode) _finalize_last_node(); | ||
| 571 | assert(nullptr == _lastNode); | ||
| 572 | _lastNodeName = name; | ||
| 573 | _lastNode = new pdef::Node(description); | ||
| 574 | auto pp = _lastNode->_set_scalar<T>(); | ||
| 575 | pp->set_validator(validator); | ||
| 576 | _lastNode->_set_scalar(pp); | ||
| 577 | return *this; | ||
| 578 | } | ||
| 579 | /// Defines parameter with default value (optional), with name and description | ||
| 580 | template<typename T> | ||
| 581 | Composer & p( const char * name | ||
| 582 | , const T & dft | ||
| 583 | , const char * description=nullptr | ||
| 584 | ) { | ||
| 585 | if(_lastNode) _finalize_last_node(); | ||
| 586 | assert(nullptr == _lastNode); | ||
| 587 | _lastNodeName = name; | ||
| 588 | _lastNode = new pdef::Node(description); | ||
| 589 | auto pp = _lastNode->_set_scalar<T>(); | ||
| 590 | pp->set(dft); | ||
| 591 | return *this; | ||
| 592 | } | ||
| 593 | /// Defines parameter with default value and validator, with name and description | ||
| 594 | template<typename T> | ||
| 595 | Composer & p( const char * name | ||
| 596 | , const T & dft | ||
| 597 | , std::shared_ptr<typename pdef::Scalar<T>::iValidator> & validator | ||
| 598 | , const char * description=nullptr | ||
| 599 | ) { | ||
| 600 | if(_lastNode) _finalize_last_node(); | ||
| 601 | assert(nullptr == _lastNode); | ||
| 602 | _lastNodeName = name; | ||
| 603 | _lastNode = new pdef::Node(description); | ||
| 604 | auto pp = _lastNode->_set_scalar<T>(); | ||
| 605 | pp->set_validator(validator); | ||
| 606 | pp->set(dft); | ||
| 607 | return *this; | ||
| 608 | } | ||
| 609 | |||
| 610 | //RuntimeCfg & start_section(const char * name, const char * description=nullptr); | ||
| 611 | //RuntimeCfg & end_section(const char * name=nullptr); | ||
| 612 | |||
| 613 | //void set(const YAML::Node &); | ||
| 614 | |||
| 615 | /// Returns node by path string | ||
| 616 | pdef::Node & get(const char * path); | ||
| 617 | |||
| 618 | /// Returns node by path string, const version | ||
| 619 | const pdef::Node & get(const char *) const; | ||
| 620 | #endif | ||
| 621 | }; | ||
| 622 | #endif | ||
| 623 | |||
| 624 | } // namespace ::na64dp::util::pdef | ||
| 625 | } // namespace ::na64dp::util | ||
| 626 | } // namespace na64dp | ||
| 627 | |||
| 628 |