mirror of https://github.com/alibaba/MNN.git
				
				
				
			
		
			
				
	
	
		
			370 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| //
 | |
| //  ConfigFile.hpp
 | |
| //  MNN
 | |
| //
 | |
| //  Created by MNN on 2019/01/22.
 | |
| //  Copyright © 2018, Alibaba Group Holding Limited
 | |
| //
 | |
| 
 | |
| #ifndef CONFIGFILE_HPP
 | |
| #define CONFIGFILE_HPP
 | |
| 
 | |
| #include <fstream>
 | |
| #include <iostream>
 | |
| #include <vector>
 | |
| #include <map>
 | |
| #include <sstream>
 | |
| #include <string>
 | |
| 
 | |
| /*
 | |
| * \brief Generic configuration Class
 | |
| * can deal with the file like below:
 | |
| *
 | |
| *           input_size = 1
 | |
| *           input_names = ImageTensor
 | |
| *           input_dims = 1x3x320x180
 | |
| *           output_size = 1
 | |
| *           output_names = strided_slice_61
 | |
| *
 | |
| */
 | |
| class ConfigFile {
 | |
|     // Data
 | |
| protected:
 | |
|     std::string m_Delimiter;                       //!< separator between key and value
 | |
|     std::string m_Comment;                         //!< separator between value and comments
 | |
|     std::map<std::string, std::string> m_Contents; //!< extracted keys and values
 | |
| 
 | |
|     typedef std::map<std::string, std::string>::iterator mapi;
 | |
|     typedef std::map<std::string, std::string>::const_iterator mapci;
 | |
|     // Methods
 | |
| public:
 | |
|     ConfigFile(std::string filename, std::string delimiter = "=", std::string comment = "#");
 | |
|     ConfigFile() = default;
 | |
|     template <class T>
 | |
|     T Read(
 | |
|         const std::string& in_key) const; //!<Search for key and read value or optional default value, call as read<T>
 | |
|     template <class T>
 | |
|     T Read(const std::string& in_key, const T& in_value) const;
 | |
|     template <class T>
 | |
|     bool ReadInto(T& out_var, const std::string& in_key) const;
 | |
|     template <class T>
 | |
|     bool ReadInto(T& out_var, const std::string& in_key, const T& in_value) const;
 | |
|     bool FileExist(std::string filename);
 | |
|     void ReadFile(std::string filename, std::string delimiter = "=", std::string comment = "#");
 | |
| 
 | |
|     // Check whether key exists in configuration
 | |
|     bool KeyExists(const std::string& in_key) const;
 | |
| 
 | |
|     // Modify keys and values
 | |
|     template <class T>
 | |
|     void Add(const std::string& in_key, const T& in_value);
 | |
|     void Remove(const std::string& in_key);
 | |
| 
 | |
|     // Check or change configuration syntax
 | |
|     std::string GetDelimiter() const {
 | |
|         return m_Delimiter;
 | |
|     }
 | |
|     std::string GetComment() const {
 | |
|         return m_Comment;
 | |
|     }
 | |
|     std::string SetDelimiter(const std::string& in_s) {
 | |
|         std::string old = m_Delimiter;
 | |
|         m_Delimiter     = in_s;
 | |
|         return old;
 | |
|     }
 | |
|     std::string SetComment(const std::string& in_s) {
 | |
|         std::string old = m_Comment;
 | |
|         m_Comment       = in_s;
 | |
|         return old;
 | |
|     }
 | |
| 
 | |
|     // Write or read configuration
 | |
|     friend std::ostream& operator<<(std::ostream& os, const ConfigFile& cf);
 | |
|     friend std::istream& operator>>(std::istream& is, ConfigFile& cf);
 | |
| 
 | |
| protected:
 | |
|     template <class T>
 | |
|     static std::string T_as_string(const T& t);
 | |
|     template <class T>
 | |
|     static T string_as_T(const std::string& s);
 | |
|     static void Trim(std::string& inout_s);
 | |
| 
 | |
|     // Exception types
 | |
| public:
 | |
|     struct File_not_found {
 | |
|         std::string filename;
 | |
|         File_not_found(const std::string& filename_ = std::string()) : filename(filename_) {
 | |
|         }
 | |
|     };
 | |
|     struct Key_not_found { // thrown only by T read(key) variant of read()
 | |
|         std::string key;
 | |
|         Key_not_found(const std::string& key_ = std::string()) : key(key_) {
 | |
|         }
 | |
|     };
 | |
| };
 | |
| 
 | |
| /* static */
 | |
| template <class T>
 | |
| std::string ConfigFile::T_as_string(const T& t) {
 | |
|     // Convert from a T to a string
 | |
|     // Type T must support << operator
 | |
|     std::ostringstream ost;
 | |
|     ost << t;
 | |
|     return ost.str();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| template <class T>
 | |
| T ConfigFile::string_as_T(const std::string& s) {
 | |
|     // Convert from a string to a T
 | |
|     // Type T must support >> operator
 | |
|     T t;
 | |
|     std::istringstream ist(s);
 | |
|     ist >> t;
 | |
|     return t;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| template <>
 | |
| inline std::string ConfigFile::string_as_T<std::string>(const std::string& s) {
 | |
|     // Convert from a string to a string
 | |
|     // In other words, do nothing
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| template <>
 | |
| inline bool ConfigFile::string_as_T<bool>(const std::string& s) {
 | |
|     // Convert from a string to a bool
 | |
|     // Interpret "false", "F", "no", "n", "0" as false
 | |
|     // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true
 | |
|     bool b          = true;
 | |
|     std::string sup = s;
 | |
|     for (std::string::iterator p = sup.begin(); p != sup.end(); ++p)
 | |
|         *p = toupper(*p); // make string all caps
 | |
|     if (sup == std::string("FALSE") || sup == std::string("F") || sup == std::string("NO") || sup == std::string("N") ||
 | |
|         sup == std::string("0") || sup == std::string("NONE"))
 | |
|         b = false;
 | |
|     return b;
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| T ConfigFile::Read(const std::string& key) const {
 | |
|     // Read the value corresponding to key
 | |
|     mapci p = m_Contents.find(key);
 | |
|     if (p == m_Contents.end()) {
 | |
|         std::cout << "Key Error!" << std::endl;
 | |
|     }
 | |
|     return string_as_T<T>(p->second);
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| T ConfigFile::Read(const std::string& key, const T& value) const {
 | |
|     // Return the value corresponding to key or given default value
 | |
|     // if key is not found
 | |
|     mapci p = m_Contents.find(key);
 | |
|     if (p == m_Contents.end())
 | |
|         return value;
 | |
|     return string_as_T<T>(p->second);
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| bool ConfigFile::ReadInto(T& var, const std::string& key) const {
 | |
|     // Get the value corresponding to key and store in var
 | |
|     // Return true if key is found
 | |
|     // Otherwise leave var untouched
 | |
|     mapci p    = m_Contents.find(key);
 | |
|     bool found = (p != m_Contents.end());
 | |
|     if (found)
 | |
|         var = string_as_T<T>(p->second);
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| bool ConfigFile::ReadInto(T& var, const std::string& key, const T& value) const {
 | |
|     // Get the value corresponding to key and store in var
 | |
|     // Return true if key is found
 | |
|     // Otherwise set var to given default
 | |
|     mapci p    = m_Contents.find(key);
 | |
|     bool found = (p != m_Contents.end());
 | |
|     if (found)
 | |
|         var = string_as_T<T>(p->second);
 | |
|     else
 | |
|         var = value;
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| template <class T>
 | |
| void ConfigFile::Add(const std::string& in_key, const T& value) {
 | |
|     // Add a key with given value
 | |
|     std::string v   = T_as_string(value);
 | |
|     std::string key = in_key;
 | |
|     Trim(key);
 | |
|     Trim(v);
 | |
|     m_Contents[key] = v;
 | |
|     return;
 | |
| }
 | |
| std::vector<int> stringToDims(const std::string& str, const std::string& pattern) {
 | |
|     std::vector<int> res;
 | |
|     if (str == "") {
 | |
|         return res;
 | |
|     }
 | |
|     std::string strs = str + pattern;
 | |
|     size_t pos       = strs.find(pattern);
 | |
| 
 | |
|     while (pos != strs.npos) {
 | |
|         std::string temp = strs.substr(0, pos);
 | |
|         std::istringstream tempIs(temp);
 | |
|         int p;
 | |
|         tempIs >> p;
 | |
|         res.push_back(p);
 | |
|         strs = strs.substr(pos + 1, strs.size());
 | |
|         pos  = strs.find(pattern);
 | |
|     }
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| std::vector<std::string> splitNames(const int size, const std::string names) {
 | |
|     std::vector<std::string> split(size);
 | |
|     std::string rest = names;
 | |
|     for (int i = 0; i < size; ++i) {
 | |
|         auto position = rest.find(",");
 | |
|         split[i]      = rest.substr(0, position);
 | |
|         rest          = rest.substr(position + 1, rest.size());
 | |
|     }
 | |
|     return split;
 | |
| }
 | |
| 
 | |
| std::vector<std::vector<int>> splitDims(const int size, const std::string string) {
 | |
|     std::vector<std::vector<int>> dims(size);
 | |
|     std::string rest = string;
 | |
|     for (int i = 0; i < size; ++i) {
 | |
|         auto position = rest.find(",");
 | |
|         dims[i]       = stringToDims(rest.substr(0, position), "x");
 | |
|         rest          = rest.substr(position + 1, rest.size());
 | |
|     }
 | |
|     return dims;
 | |
| }
 | |
| 
 | |
| ConfigFile::ConfigFile(std::string filename, std::string delimiter, std::string comment) : m_Delimiter(delimiter), m_Comment(comment) {
 | |
|     // Construct a ConfigFile, getting keys and values from given file
 | |
| 
 | |
|     std::ifstream in(filename.c_str());
 | |
|     in >> (*this);
 | |
| }
 | |
| 
 | |
| bool ConfigFile::KeyExists(const std::string& key) const {
 | |
|     // Indicate whether key is found
 | |
|     mapci p = m_Contents.find(key);
 | |
|     return (p != m_Contents.end());
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void ConfigFile::Trim(std::string& inout_s) {
 | |
|     // Remove leading and trailing whitespace
 | |
|     static const char whitespace[] = " \n\t\v\r\f";
 | |
|     inout_s.erase(0, inout_s.find_first_not_of(whitespace));
 | |
|     inout_s.erase(inout_s.find_last_not_of(whitespace) + 1U);
 | |
| }
 | |
| 
 | |
| std::ostream& operator<<(std::ostream& os, const ConfigFile& cf) {
 | |
|     // Save a ConfigFile to os
 | |
|     for (ConfigFile::mapci p = cf.m_Contents.begin(); p != cf.m_Contents.end(); ++p) {
 | |
|         os << p->first << " " << cf.m_Delimiter << " ";
 | |
|         os << p->second << std::endl;
 | |
|     }
 | |
|     return os;
 | |
| }
 | |
| 
 | |
| void ConfigFile::Remove(const std::string& key) {
 | |
|     // Remove key and its value
 | |
|     m_Contents.erase(m_Contents.find(key));
 | |
|     return;
 | |
| }
 | |
| 
 | |
| std::istream& operator>>(std::istream& is, ConfigFile& cf) {
 | |
|     // Load a ConfigFile from is
 | |
|     // Read in keys and values, keeping internal whitespace
 | |
|     typedef std::string::size_type pos;
 | |
|     const std::string& delim = cf.m_Delimiter; // separator
 | |
|     const std::string& comm  = cf.m_Comment;   // comment
 | |
|     const pos skip      = delim.length(); // length of separator
 | |
| 
 | |
|     std::string nextline = ""; // might need to read ahead to see where value ends
 | |
| 
 | |
|     while (is || nextline.length() > 0) {
 | |
|         // Read an entire line at a time
 | |
|         std::string line;
 | |
|         if (nextline.length() > 0) {
 | |
|             line     = nextline; // we read ahead; use it now
 | |
|             nextline = "";
 | |
|         } else {
 | |
|             std::getline(is, line);
 | |
|         }
 | |
| 
 | |
|         // Ignore comments
 | |
|         line = line.substr(0, line.find(comm));
 | |
| 
 | |
|         // Parse the line if it contains a delimiter
 | |
|         pos delimPos = line.find(delim);
 | |
|         if (delimPos < std::string::npos) {
 | |
|             // Extract the key
 | |
|             std::string key = line.substr(0, delimPos);
 | |
|             line.replace(0, delimPos + skip, "");
 | |
| 
 | |
|             // See if value continues on the next line
 | |
|             // Stop at blank line, next line with a key, end of stream,
 | |
|             // or end of file sentry
 | |
|             bool terminate = false;
 | |
|             while (!terminate && is) {
 | |
|                 std::getline(is, nextline);
 | |
|                 terminate = true;
 | |
| 
 | |
|                 std::string nlcopy = nextline;
 | |
|                 ConfigFile::Trim(nlcopy);
 | |
|                 if (nlcopy == "")
 | |
|                     continue;
 | |
| 
 | |
|                 nextline = nextline.substr(0, nextline.find(comm));
 | |
|                 if (nextline.find(delim) != std::string::npos)
 | |
|                     continue;
 | |
| 
 | |
|                 nlcopy = nextline;
 | |
|                 ConfigFile::Trim(nlcopy);
 | |
|                 if (nlcopy != "")
 | |
|                     line += "\n";
 | |
|                 line += nextline;
 | |
|                 terminate = false;
 | |
|             }
 | |
| 
 | |
|             // Store key and value
 | |
|             ConfigFile::Trim(key);
 | |
|             ConfigFile::Trim(line);
 | |
|             cf.m_Contents[key] = line; // overwrites if key is repeated
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return is;
 | |
| }
 | |
| bool ConfigFile::FileExist(std::string filename) {
 | |
|     bool exist = false;
 | |
|     std::ifstream in(filename.c_str());
 | |
|     if (in)
 | |
|         exist = true;
 | |
|     return exist;
 | |
| }
 | |
| 
 | |
| void ConfigFile::ReadFile(std::string filename, std::string delimiter, std::string comment) {
 | |
|     m_Delimiter = delimiter;
 | |
|     m_Comment   = comment;
 | |
|     std::ifstream in(filename.c_str());
 | |
| 
 | |
|     if (!in) {
 | |
|         std::cout << "file is not existed!" << std::endl;
 | |
|     }
 | |
| 
 | |
|     in >> (*this);
 | |
| }
 | |
| #endif // CONFIG_HPP
 |