Skip to content
Snippets Groups Projects
Strings.cpp 41.4 KiB
Newer Older
       *  used to generate path in hdf file, so the resulting path has to obey hdf constrains;
       */
      size_t split_path(const std::string &path, std::vector<std::string> &path_components)
      {
        if(path.empty()){
          path_components.resize(0);
          return 0;
        }
        // convert Windows path into the unix one
        std::string working_path(path);
        for(size_t i=0;i<path.size();i++){
          if(working_path[i]<0x20||working_path[i]>0x7E)working_path[i]='_';
          if(working_path[i]=='\\')working_path[i]='/';
          if(working_path[i]==' ')working_path[i]='_';
        }


        // path start with relative character, and we need to convert it into full path
        if(path[0]=='.'){
          // get absolute path using working directory as base;
          Poco::Path absol;
          absol = absol.absolute();
          working_path = absol.toString(Poco::Path::PATH_UNIX)+working_path;
        }
        // as poco splt using regular expressions is doing some rubbish, we need to do split manually
        // code below implements perl split(/\\//,string) commamd. (\\ has been converted to / above)
        std::list<int64_t> split_pos;
        split_pos.push_back(-1);
        size_t path_size = working_path.size();
        for(size_t i=0;i<path_size;i++){
          if(working_path[i]=='/'){
Alex Buts's avatar
Alex Buts committed
            split_pos.push_back(i);
        split_pos.push_back(path_size);
        // allocate target vector to keep folder structure and fill it in
        size_t n_folders = split_pos.size()-1;
        path_components.resize(n_folders);
        std::list<int64_t>::iterator it1 = split_pos.begin();
        std::list<int64_t>::iterator it2 = it1;
        ++it2;

        int64_t ic(0);
        for(; it2!=split_pos.end();++it2){
          std::string folder = working_path.substr(*it1+1,*it2-*it1-1);
          if(folder.empty()||(folder.size()==1&&folder==".")){ // skip self-references and double slashes;
Alex Buts's avatar
Alex Buts committed
            it1=it2;
            continue;
          }
          // reprocess up-references;
          if(folder==".."){
Alex Buts's avatar
Alex Buts committed
            if(folder.size()!=2)throw(std::invalid_argument("path contains wrong path group"));
            ic--;
            if(ic<0)throw(std::invalid_argument("path contains relative references to a folder outside of the seach tree"));
            it1=it2;
            continue;
          }
          path_components[ic]=folder;
          ic++;
          it1=it2;
        n_folders=size_t(ic);
        path_components.resize(n_folders);
        return n_folders;
      }

      /**
       * Function checks if the candidate is the member of the group
       * @param group :: vector of string to check
       * @param candidate :: the string which has to be checked against the group
       * @returns :: number of the candidate in the input vector of strings if the candidate belongs to the group
                     or -1 if it does not.
                     Returns the number of the first maching entry in the group if there are duplicated entries in the group
       */
      int isMember(const std::vector<std::string> &group, const std::string &candidate)
      {
        int num(-1);
        for(size_t i=0;i<group.size();i++){
          if(candidate.compare(group[i])==0){
Alex Buts's avatar
Alex Buts committed
            num = int(i);
            return num;
Alex Buts's avatar
Alex Buts committed
        }
      /**
       * Parses a number range, e.g. "1,4-9,54-111,3,10", to the vector containing all the elements 
       * within the range. 
       * @param str String to parse
       * @param elemSep String with characters used to separate elements (',')
       * @param rangeSep String with characters used to separate range start and end ('-')
       * @return A vector with all the elements from the range
       */
      std::vector<int> parseRange(const std::string& str, const std::string& elemSep, 
                                  const std::string& rangeSep)
      {
        typedef Poco::StringTokenizer Tokenizer;

        boost::shared_ptr<Tokenizer> elements;

        if(elemSep.find(' ') != std::string::npos)
        {
          // If element separator contains space character it's a special case, because in that case
          // it is allowed to have element separator inside a range, e.g. "4 - 5", but not "4,-5"

          // Space is added so that last empty element of the "1,2,3-" is not ignored and we can 
          // spot the error. Behaviour is changed in Poco 1.5 and this will not be needed.
          Tokenizer ranges(str + " ", rangeSep, Tokenizer::TOK_TRIM);
          std::string new_str = join(ranges.begin(), ranges.end(), rangeSep.substr(0,1));

          elements = boost::make_shared<Tokenizer>(new_str, elemSep, Tokenizer::TOK_IGNORE_EMPTY | Tokenizer::TOK_TRIM);
        }
        else
        {
          elements = boost::make_shared<Tokenizer>(str, elemSep, Tokenizer::TOK_IGNORE_EMPTY | Tokenizer::TOK_TRIM);
        }

        std::vector<int> result;

        // Estimation of the resulting number of elements
        result.reserve(elements->count());

        for (Tokenizer::Iterator it = elements->begin(); it != elements->end(); it++)
        {
          // See above for the reason space is added
          Tokenizer rangeElements(*it + " ", rangeSep, Tokenizer::TOK_TRIM);

          size_t noOfRangeElements = rangeElements.count();

          // A single element
          if(noOfRangeElements == 1)
          {
            int element;
            if(convert(rangeElements[0], element) != 1)
              throw std::invalid_argument("Invalid element: " + *it);
            result.push_back(element);
          }
          // A pair
          else if(noOfRangeElements == 2)
          {
            int start, end;

            if(convert(rangeElements[0], start) != 1 || convert(rangeElements[1], end) != 1)
              throw std::invalid_argument("Invalid range: " + *it);

            if(start >= end)
              throw std::invalid_argument("Range boundaries are reversed: " + *it);

            for(int i = start; i <= end; i++)
              result.push_back(i);
          }
          // Error - e.g. "--""
          else
          {
            throw std::invalid_argument("Multiple range separators: " + *it);
          }
        }

        return result;
      }

      /// \cond TEMPLATE
      template MANTID_KERNEL_DLL int section(std::string&,double&);
      template MANTID_KERNEL_DLL int section(std::string&,float&);
      template MANTID_KERNEL_DLL int section(std::string&,int&);
      template MANTID_KERNEL_DLL int section(std::string&,std::string&);

      template MANTID_KERNEL_DLL int sectPartNum(std::string&,double&);
      template MANTID_KERNEL_DLL int sectPartNum(std::string&,int&);
      template MANTID_KERNEL_DLL int sectionMCNPX(std::string&,double&);

      template MANTID_KERNEL_DLL int convert(const std::string&,double&);
      template MANTID_KERNEL_DLL int convert(const std::string&,float&);
      template MANTID_KERNEL_DLL int convert(const std::string&,std::string&);
      template MANTID_KERNEL_DLL int convert(const std::string&,int&);
      template MANTID_KERNEL_DLL int convert(const std::string&,std::size_t&);
      template MANTID_KERNEL_DLL int convert(const std::string&,bool&);
      template MANTID_KERNEL_DLL int convert(const char*,std::string&);
      template MANTID_KERNEL_DLL int convert(const char*,double&);
      template MANTID_KERNEL_DLL int convert(const char*,int&);
      template MANTID_KERNEL_DLL int convert(const char*,std::size_t&);
      template MANTID_KERNEL_DLL int convert(const char*,bool&);
Nick Draper's avatar
Nick Draper committed
      template MANTID_KERNEL_DLL std::string toString(const double &value);
      template MANTID_KERNEL_DLL std::string toString(const float &value);
      template MANTID_KERNEL_DLL std::string toString(const int &value);
      template MANTID_KERNEL_DLL std::string toString(const uint16_t &value);
      template MANTID_KERNEL_DLL std::string toString(const size_t &value); // Matches uint64_t on Linux 64 & Win 64
#if defined(__APPLE__) || ( defined(_WIN32) && !defined(_WIN64)) || (defined(__GNUC__) && !defined(__LP64__)) // Mac or 32-bit compiler
Nick Draper's avatar
Nick Draper committed
      template MANTID_KERNEL_DLL std::string toString(const uint64_t &value);
Nick Draper's avatar
Nick Draper committed
      template MANTID_KERNEL_DLL std::string toString(const std::string &value);
      template MANTID_KERNEL_DLL std::string toString(const std::vector<int> &value);
      template MANTID_KERNEL_DLL std::string toString(const UnitLabel &value);
      // this block should generate the vector ones as well
      template MANTID_KERNEL_DLL std::string toString(const std::set<int> &value);
      template MANTID_KERNEL_DLL std::string toString(const std::set<int16_t> &value);
      template MANTID_KERNEL_DLL std::string toString(const std::set<size_t> &value); // Matches uint64_t on Linux 64 & Win 64
#if defined(__APPLE__) || ( defined(_WIN32) && !defined(_WIN64)) || (defined(__GNUC__) && !defined(__LP64__)) // Mac or 32-bit compiler
      template MANTID_KERNEL_DLL std::string toString(const std::set<uint64_t> &value);
      template MANTID_KERNEL_DLL int convPartNum(const std::string&,double&);
      template MANTID_KERNEL_DLL int convPartNum(const std::string&,int&);
      template MANTID_KERNEL_DLL int setValues(const std::string&,const std::vector<int>&,std::vector<double>&);
      template MANTID_KERNEL_DLL int writeFile(const std::string&,const double&,const std::vector<double>&);
      template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<double>&,const std::vector<double>&,const std::vector<double>&);
      template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<double>&,const std::vector<double>&);
      template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<float>&,const std::vector<float>&);
      template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<float>&,const std::vector<float>&,const std::vector<float>&);
      /// \endcond TEMPLATE