Page MenuHomec4science

safe_config.hpp
No OneTemporary

File Metadata

Created
Thu, Aug 15, 16:25

safe_config.hpp

/* =============================================================================
Copyright (c) 2014 - 2016
F. Georget <fabieng@princeton.edu> Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
============================================================================= */
#ifndef SPECMICP_UTILS_SAFECONFIG_HPP
#define SPECMICP_UTILS_SAFECONFIG_HPP
//! \file safe_config.hpp
//! \brief YAML configuration file reader
//!
//! This is a set of wrappers over the yaml-cpp API
#include "specmicp_common/types.hpp"
#include "specmicp_common/pimpl_ptr.hpp"
#include <string>
#include <memory>
#include <yaml-cpp/node/detail/iterator_fwd.h>
namespace YAML {
class Node;
} //end namespace YAML
namespace specmicp {
namespace io {
//! \brief Type of error that can be reported
enum class YAMLConfigError
{
UnknownError,
UnknownVariable,
MissingRequiredAttribute,
MissingRequiredSection,
InvalidArgument,
ConversionError,
ListExpected,
MapExpected
};
// internal store required information
//! \internal
struct SPECMICP_DLL_LOCAL YAMLConfigFileHandle;
//! \brief Access to the configuration
class SPECMICP_DLL_PUBLIC YAMLConfigHandle
{
public:
//! \brief Report an error
void report_error(
YAMLConfigError error_type,
const std::string& error_msg
);
//! \brief Return true if it is a sequence
bool is_sequence();
//! \brief Return true if sub-node exists and is a sequence
bool is_sequence(const std::string& node);
//! \brief Return true if sub-node exists and is a map
bool is_map(const std::string& node);
//! \brief Return true if it is a map
bool is_map();
//! \brief Return true if sub-node exist
bool has_node(const std::string& node);
//! \brief Return true if sub-node exist
bool has_node(uindex_t value);
//! \brief Return true if the node has the given attribute
//!
//! An attribute is a pair key/value, where the value is
//! neither a map or a sequence
bool has_attribute(const std::string& attribute);
//! \brief Return true if the node has the given section
//!
//! A section is a pair key/value, where the value is a
//! map or a sequence
bool has_section(const std::string& section);
//! \brief Return true if the node has the given section
//!
//! A section is a pair key/value, where the value is a
//! map or a sequence
bool has_section(uindex_t value);
//! \brief Return the number of element in the section
uindex_t size();
//! \brief Return a section from a map
YAMLConfigHandle get_section(const std::string& section);
//! \brief Return a section from a list
YAMLConfigHandle get_section(uindex_t value);
//! \brief Return an attribute
template <typename T>
T get_attribute(const std::string& attribute);
//! \brief Return a lower bounded scalar attribute
template <typename T>
T get_attribute(const std::string& attribute,
T lower_bound
);
//! \brief Return a bounded scalar attribute
template <typename T>
T get_attribute(const std::string& attribute,
T lower_bound,
T upper_bound
);
//! \brief Return a value in a list
template <typename T>
T get_value(uindex_t ind);
//! \brief Return a required attribute
template <typename T>
T get_required_attribute(const std::string& attribute);
//! \brief Return a required attribute
template <typename T>
T get_required_attribute(
const std::string& attribute,
T lower_bound
);
//! \brief Return a required attribute
template <typename T>
T get_required_attribute(
const std::string& attribute,
T lower_bound,
T upper_bound
);
//! \brief Return an optional attribute
template <typename T>
T get_optional_attribute(
const std::string& attribute,
const T& default_value
);
//! \brief Return an optional attribute
template <typename T>
T get_optional_attribute(
const std::string& attribute,
const T& default_value,
T lower_bound
);
//! \brief Return an optional attribute
template <typename T>
T get_optional_attribute(
const std::string& attribute,
const T& default_value,
T lower_bound,
T upper_bound
);
//! \brief Set a variable if the attribute exists
template <typename T>
void set_if_attribute_exists(
T& var_to_set,
const std::string& attribute
);
template <typename T>
void set_if_attribute_exists(
T& var_to_set,
const std::string& attribute,
T lower_bound
);
template <typename T>
void set_if_attribute_exists(
T& var_to_set,
const std::string& attribute,
T lower_bound,
T upper_bound
);
template <typename T=index_t>
void set_if_attribute_exists(
int& var_to_set,
const std::string& attribute
);
template <typename T=index_t>
void set_if_attribute_exists(
int& var_to_set,
const std::string& attribute,
T lower_bound
);
//! \brief Return a list of values for a list attribute
template <typename T>
std::vector<T> list_to_vector(const std::string& list);
~YAMLConfigHandle();
YAMLConfigHandle& operator= (const YAMLConfigHandle& other);
YAMLConfigHandle(const YAMLConfigHandle& other);
YAMLConfigHandle(YAMLConfigHandle&& other);
protected:
// can only be created from a file or another handle
YAMLConfigHandle(
const YAML::Node& node,
std::shared_ptr<YAMLConfigFileHandle> const file_handle,
const std::string& section,
const std::string& path);
void set_file_handle(std::shared_ptr<YAMLConfigFileHandle> file_handle);
private:
struct SPECMICP_DLL_LOCAL YAMLConfigHandleImpl;
utils::pimpl_ptr<YAMLConfigHandleImpl> m_impl;
public:
//! Iterator over a map
class MapIterator
{
friend YAMLConfigHandle;
public:
MapIterator(MapIterator&& other);
~MapIterator();
std::pair<std::string, std::string> operator* ();
MapIterator& operator++ ();
bool operator==(const MapIterator& other);
bool operator!=(const MapIterator& other);
private:
MapIterator(
YAMLConfigHandleImpl* handle,
std::unique_ptr<YAML::iterator> it
);
YAMLConfigHandleImpl* m_handle;
std::unique_ptr<YAML::iterator> m_true_it;
};
MapIterator map_begin();
MapIterator map_end();
};
// ======================= //
// YAMLConfigFile //
// ======================= //
//! \brief This class represent a file
//!
//! It must be alive while the config is accessed
class SPECMICP_DLL_PUBLIC YAMLConfigFile:
public YAMLConfigHandle
{
public:
static YAMLConfigFile load(
const std::string& file
);
static YAMLConfigFile load_from_string(
const std::string& str,
std::string name=""
);
static std::unique_ptr<YAMLConfigFile> make(
const std::string& file
);
static std::unique_ptr<YAMLConfigFile> make_from_string(
const std::string& str,
std::string name=""
);
~YAMLConfigFile();
private:
YAMLConfigFile(
const YAML::Node& node,
const std::string name
);
std::shared_ptr<YAMLConfigFileHandle> m_handle;
};
// ======================= //
// Template implementation //
// ======================= //
// explicit specialization
template <>
scalar_t YAMLConfigHandle::get_attribute(const std::string& attribute);
template <>
index_t YAMLConfigHandle::get_attribute(const std::string& attribute);
template <>
uindex_t YAMLConfigHandle::get_attribute(const std::string& attribute);
template <>
bool YAMLConfigHandle::get_attribute(const std::string& attribute);
template <>
std::string YAMLConfigHandle::get_attribute(const std::string& attribute);
template <typename T>
T YAMLConfigHandle::get_attribute(
const std::string& attribute,
T lower_bound,
T upper_bound)
{
T value = get_attribute<T>(attribute);
if (value < lower_bound or value > upper_bound) {
report_error(
YAMLConfigError::InvalidArgument,
"Attribute '" + attribute + "' is required to"
" be between " + std::to_string(lower_bound)
+ " and " + std::to_string(upper_bound)
+ " (Got : " + std::to_string(value) + ")."
);
}
return value;
}
template <typename T>
T YAMLConfigHandle::get_attribute(
const std::string& attribute,
T lower_bound
)
{
T value = get_attribute<T>(attribute);
if (value < lower_bound ) {
report_error(
YAMLConfigError::InvalidArgument,
"Attribute '" + attribute + "' is required to"
" be greater than " + std::to_string(lower_bound)
+ " (Got : " + std::to_string(value) + ")."
);
}
return value;
}
template <>
scalar_t YAMLConfigHandle::get_value(uindex_t ind);
template <>
index_t YAMLConfigHandle::get_value(uindex_t ind);
template <>
uindex_t YAMLConfigHandle::get_value(uindex_t ind);
template <>
bool YAMLConfigHandle::get_value(uindex_t ind);
template <>
std::string YAMLConfigHandle::get_value(uindex_t ind);
template <>
std::vector<scalar_t> YAMLConfigHandle::list_to_vector(const std::string& list);
template <>
std::vector<index_t> YAMLConfigHandle::list_to_vector(const std::string& list);
template <>
std::vector<index_t> YAMLConfigHandle::list_to_vector(const std::string& list);
template <>
std::vector<bool> YAMLConfigHandle::list_to_vector(const std::string& list);
template <>
std::vector<std::string> YAMLConfigHandle::list_to_vector(const std::string& list);
// Required attribute
// ------------------
template <typename T>
T YAMLConfigHandle::get_required_attribute(const std::string& attribute)
{
if (not has_attribute(attribute)) {
report_error(YAMLConfigError::MissingRequiredAttribute,
attribute);
}
return get_attribute<T>(attribute);
}
template <typename T>
T YAMLConfigHandle::get_required_attribute(
const std::string& attribute,
T lower_bound
)
{
if (not has_attribute(attribute)) {
report_error(YAMLConfigError::MissingRequiredAttribute,
attribute);
}
return get_attribute<T>(attribute, lower_bound);
}
template <typename T>
T YAMLConfigHandle::get_required_attribute(
const std::string& attribute,
T lower_bound,
T upper_bound
)
{
if (not has_attribute(attribute)) {
report_error(YAMLConfigError::MissingRequiredAttribute,
attribute);
}
return get_attribute<T>(attribute, lower_bound, upper_bound);
}
// Optional attribute
// ------------------
template <typename T>
T YAMLConfigHandle::get_optional_attribute(
const std::string& attribute,
const T& default_value)
{
if (not has_attribute(attribute)) {
return default_value;
}
return get_attribute<T>(attribute);
}
template <typename T>
T YAMLConfigHandle::get_optional_attribute(
const std::string& attribute,
const T& default_value,
T lower_bound
)
{
if (not has_attribute(attribute)) {
return default_value;
}
return get_attribute<T>(attribute, lower_bound);
}
//! \brief Return an optional attribute
template <typename T>
T YAMLConfigHandle::get_optional_attribute(
const std::string& attribute,
const T& default_value,
T lower_bound,
T upper_bound
)
{
if (not has_attribute(attribute)) {
return default_value;
}
return get_attribute<T>(attribute, lower_bound, upper_bound);
}
// Set if attribute exists
// -----------------------
template <typename T>
void YAMLConfigHandle::set_if_attribute_exists(
T& var_to_set,
const std::string& attribute
)
{
if (has_attribute(attribute)) {
var_to_set = get_attribute<T>(attribute);
}
}
template <typename T>
void YAMLConfigHandle::set_if_attribute_exists(
int& var_to_set,
const std::string& attribute
)
{
if (has_attribute(attribute)) {
var_to_set = static_cast<int>(get_attribute<T>(attribute));
}
}
template <typename T>
void YAMLConfigHandle::set_if_attribute_exists(
T& var_to_set,
const std::string& attribute,
T lower_bound,
T upper_bound
)
{
if (has_attribute(attribute)) {
var_to_set = get_attribute<T>(attribute, lower_bound, upper_bound);
}
}
template <typename T>
void YAMLConfigHandle::set_if_attribute_exists(
T& var_to_set,
const std::string& attribute,
T lower_bound
)
{
if (has_attribute(attribute)) {
var_to_set = get_attribute<T>(attribute, lower_bound);
}
}
template <typename T>
void YAMLConfigHandle::set_if_attribute_exists(
int& var_to_set,
const std::string& attribute,
T lower_bound
)
{
if (has_attribute(attribute)) {
var_to_set = get_attribute<T>(attribute, lower_bound);
}
}
} //end namespace io
} //end namespace specmicp
#endif // SPECMICP_UTILS_SAFECONFIG_HPP

Event Timeline