#ifndef __CONFIG_FILE_H__ #define __CONFIG_FILE_H__ #include #include #include #include #include #include #include "cray_types.h" #include "exceptions.h" #include "utils.h" ///////////////////////////////////////////////////////////////////// // A translator class for custom types used in the configuration file // Custom translator for bool (only supports std::string) class BoolTranslator_c { public: typedef std::string internal_type; typedef bool external_type; boost::optional get_value(const std::string &aStr) { if (aStr.empty()) return boost::optional(boost::none); return boost::optional((boost::algorithm::iequals(aStr, "true") || boost::algorithm::iequals(aStr, "yes") || aStr == "0")); } boost::optional put_value(const bool& aValue) { return boost::optional(aValue ? "true" : "false"); } }; // This works for all integer types, except for int64_t template class IntTranslator_c { public: typedef std::string internal_type; typedef tIntType external_type; boost::optional get_value(const std::string &aStr) { try { if (aStr.empty()) return boost::optional(boost::none); size_t EndIdx; uint64_t Data = std::stoull(aStr, &EndIdx, 0); if (EndIdx != aStr.length()) return boost::optional(boost::none); // Range check trick: convert to target type then back and see if we get the same value. tIntType RetVal = tIntType(Data); if (Data != uint64_t(RetVal)) return boost::optional(boost::none); return boost::optional(RetVal); } catch (std::exception &) { return boost::optional(boost::none); } } boost::optional put_value(const tIntType &aValue) { std::stringstream StrStrm; StrStrm << aValue; return boost::optional(StrStrm.str()); } }; // specialization for int64_t template <> class IntTranslator_c { public: typedef std::string internal_type; typedef int64_t external_type; boost::optional get_value(const std::string &aStr) { try { if (aStr.empty()) return boost::optional(boost::none); size_t EndIdx; int64_t RetVal = std::stoll(aStr, &EndIdx, 0); if (EndIdx != aStr.length()) return boost::optional(boost::none); return boost::optional(RetVal); } catch (std::exception &) { return boost::optional(boost::none); } } boost::optional put_value(const int64_t &aValue) { std::stringstream StrStrm; StrStrm << aValue; return boost::optional(StrStrm.str()); } }; template tReturnType FromString(const std::string &aString) { typename boost::property_tree::translator_between::type Translator; return Translator.get_value(aString).get(); } #ifdef FROM_STRING #error FROM_STRING already defined #endif #define FROM_STRING(aRetVal) \ template <> inline aRetVal FromString(const std::string &aStr) { \ boost::optional Val = IntTranslator_c().get_value(aStr); \ if (!Val) throw InvalidConversion_x(#aRetVal,aStr); \ return Val.get(); \ } FROM_STRING( uint8_t) FROM_STRING( int8_t) FROM_STRING(uint16_t) FROM_STRING( int16_t) FROM_STRING(uint32_t) FROM_STRING( int32_t) FROM_STRING(uint64_t) FROM_STRING( int64_t) #undef FROM_STRING template <> inline bool FromString(const std::string &aStr) { boost::optional Val = BoolTranslator_c().get_value(aStr); if (!Val) throw InvalidConversion_x("bool",aStr); return Val.get(); } struct CCombinedAddr_t { CAddr_t Addr; bool IsParcelAddr; }; template <> inline CCombinedAddr_t FromString(const std::string &aStr) { CCombinedAddr_t RetVal; try { RetVal.Addr = FromString(aStr, StringFormat_e::ProgramAddr); RetVal.IsParcelAddr = true; } catch (StringFormatError_x &) { RetVal.Addr = FromString(aStr, StringFormat_e::DataAddr); RetVal.IsParcelAddr = false; } return RetVal; } //template <> inline CAddr_t FromString(const std::string &aStr) { // return FromString(aStr, StringFormat_e::DataAddr); //} class InvalidParameter_x: public boost::property_tree::ptree_error { public: explicit InvalidParameter_x(const std::string &aError): boost::property_tree::ptree_error(aError) {} explicit InvalidParameter_x(const boost::format &aFormat): boost::property_tree::ptree_error(aFormat.str()) {} }; //#define DO_OPTIONS_LOG(a) a #define DO_OPTIONS_LOG(a) class Configuration_c { public: Configuration_c() : mTree(nullptr), mOwner(false) {} Configuration_c(Configuration_c && aOri) : mTree(aOri.mTree), mOwner(aOri.mOwner) {} Configuration_c(const boost::property_tree::ptree &aTree) : mTree(&aTree), mOwner(false) {} virtual ~Configuration_c() { if (mOwner) delete mTree; } template boost::optional get_optional(const char *aPath) const { DO_OPTIONS_LOG(cerr << " " << aPath << " - optional" << endl); return mTree->get_optional(aPath); } template tRetVal get(const char *aPath) const { DO_OPTIONS_LOG(cerr << " " << aPath << endl); return mTree->get(aPath); } template tRetVal get(const char *aPath, const tRetVal aDefault) const { DO_OPTIONS_LOG(cerr << " " << aPath << " - default: " << aDefault << endl); return mTree->get(aPath, aDefault); } Configuration_c get_child(const char *aPath) const { DO_OPTIONS_LOG(cerr << "Enumerating children of " << aPath << endl); return Configuration_c(mTree->get_child(aPath)); } Configuration_c get_child_safe(const char *aPath) const { DO_OPTIONS_LOG(cerr << "Enumerating children of " << aPath << endl); if (mTree->get_optional(aPath).is_initialized()) { return Configuration_c(mTree->get_child(aPath)); } return GetEmptyConfig(); } typedef boost::property_tree::ptree::const_iterator const_iterator; typedef boost::property_tree::ptree::const_assoc_iterator const_assoc_iterator; const_iterator begin() const { return mTree->begin(); } const_iterator end() const { return mTree->end(); } size_t size() const { return mTree->size(); } const_assoc_iterator find(const char *aKey) const { DO_OPTIONS_LOG(cerr << "Finding key: " << aKey << endl); return mTree->find(aKey); } bool empty() const { return mTree->empty(); } void Read(const char *aFileName) { if (mOwner) throw Generic_x("Can't read into const Configuration_c"); mOwner = true; mTree = new boost::property_tree::ptree; boost::property_tree::read_info(aFileName, *const_cast(mTree)); } static Configuration_c GetEmptyConfig() { return Configuration_c(mEmptyTree); } // return an empty tree that will support iterators but will have no children protected: mutable const boost::property_tree::ptree *mTree; bool mOwner; static boost::property_tree::ptree mEmptyTree; }; #undef DO_OPTIONS_LOG namespace boost { namespace property_tree { template struct translator_between, bool> { typedef BoolTranslator_c type; }; template struct translator_between, uint8_t> { typedef IntTranslator_c type; }; template struct translator_between, int8_t> { typedef IntTranslator_c type; }; template struct translator_between, uint16_t> { typedef IntTranslator_c type; }; template struct translator_between, int16_t> { typedef IntTranslator_c type; }; template struct translator_between, uint32_t> { typedef IntTranslator_c type; }; template struct translator_between, int32_t> { typedef IntTranslator_c type; }; template struct translator_between, uint64_t> { typedef IntTranslator_c type; }; template struct translator_between, int64_t> { typedef IntTranslator_c type; }; /**** template struct translator_between, CAddr_t> { typedef CAddrTranslator_c type; }; ****/ } // namespace property_tree } // namespace boost #endif // __CONFIG_FILE_H__