typename.cc
Go to the documentation of this file.
00001 #include "typename.hh"
00002 #include <boost/static_assert.hpp>
00003 #include <utilmm/stringtools.hh>
00004 #include <iostream>
00005 
00006 using namespace std;
00007 using namespace boost;
00008 using namespace Typelib;
00009 using namespace utilmm;
00010 
00011 namespace
00012 {
00013     typedef std::string::value_type   NamespaceMarkType;
00014     static const NamespaceMarkType    NamespaceMark = '/';
00015     static const char*                NamespaceMarkString = "/";
00016 
00017     struct NameSeparator : public char_separator<NamespaceMarkType>
00018     {
00019         NameSeparator()
00020             : char_separator<NamespaceMarkType>(NamespaceMarkString, "", boost::keep_empty_tokens) {}
00021     };
00022     typedef boost::tokenizer<NameSeparator> NameTokenizer;
00023     
00024     // helper function which checks that \c identifier does contain
00025     // only valid characters. Note that identifier is supposed
00026     // to be a normalized name, so that it cannot be empty
00027     bool isValidIdentifier(const string& identifier)
00028     {
00029         if (identifier.empty())   return false;
00030 
00031         const int length(identifier.length());
00032         for (int i = 0; i < length; ++i)
00033         {
00034             string::value_type c(identifier[i]);
00035             if (c != '_' && c != ' ' && !isalnum(c) && c != '<' && c != '>')
00036                 return false;
00037         }
00038 
00039         return true;
00040     }
00041 }
00042 
00043 namespace Typelib
00044 {
00045     bool isAbsoluteName(const string& identifier)
00046     {
00047         if (identifier.empty()) return false;
00048         return identifier[0] == NamespaceMark;
00049     }
00050 
00051     static bool isValidTypeBasename(std::string s, bool absolute, bool accept_integers)
00052     {
00053         if (accept_integers && s.find_first_not_of("0123456789") == string::npos)
00054             return true;
00055 
00056         int pos = 0;
00057         if (absolute && s[0] != '/')
00058             return false;
00059 
00060         if (s[0] == '/')
00061             ++pos;
00062 
00063         size_t modifiers = s.find_first_of("*[");
00064         if (modifiers != string::npos)
00065             return isValidIdentifier(string(s, pos, modifiers - pos));
00066         else
00067             return isValidIdentifier(string(s, pos));
00068 
00069     }
00070 
00071     std::list<std::string> splitTypename(std::string const& name)
00072     {
00073         unsigned int start_pos = 0;
00074         if (name[0] == '/')
00075             start_pos++;
00076 
00077         int template_level = 0;
00078         std::list<std::string> result;
00079         for (unsigned int i = start_pos; i < name.length(); ++i)
00080         {
00081             if (name[i] == '/')
00082             {
00083                 if (template_level == 0)
00084                 {
00085                     result.push_back(string(name, start_pos, i - start_pos));
00086                     start_pos = i + 1;
00087                 }
00088             }
00089             else if (name[i] == '<')
00090                 template_level++;
00091             else if (name[i] == '>')
00092                 template_level--;
00093         }
00094         if (start_pos < name.length())
00095             result.push_back(string(name, start_pos, name.length() - start_pos));
00096 
00097         return result;
00098     }
00099 
00100     static pair<bool, int> isValidTypename(std::string const& s, int pos, bool absolute, bool accept_integers)
00101     {
00102         unsigned int start_pos = pos;
00103         if (s[pos] == '/')
00104             pos++;
00105 
00106         for (unsigned int i = pos; i < s.length(); ++i)
00107         {
00108             if (s[i] == '/')
00109             {
00110                 if (!isValidTypeBasename(string(s, start_pos, i - start_pos), absolute, accept_integers))
00111                     return make_pair(false, i);
00112                 start_pos = i;
00113             }
00114             else if (s[i] == '<')
00115             {
00116                 if (!isValidTypeBasename(string(s, start_pos, i - start_pos), absolute, accept_integers))
00117                     return make_pair(false, i);
00118 
00119                 while (s[i] != '>')
00120                 {
00121                     pair<bool, int> valid_arg = isValidTypename(s, i + 1, true, true);
00122                     i = valid_arg.second;
00123 
00124                     if (!valid_arg.first)
00125                         return valid_arg;
00126                     else if (i == s.length() || (s[i] != ',' && s[i] != '>'))
00127                         return make_pair(false, i);
00128                 }
00129 
00130                 start_pos = i + 1;
00131                 if (i + 1 < s.length())
00132                 {
00133                     if (s[i + 1] == '/')
00134                         i++;
00135                     else if (s[i + 1] != '>' && s[i + 1] != '[' && s[i + 1] != ',')
00136                         return make_pair(false, i + 1);
00137                 }
00138             }
00139             else if (s[i] == '[')
00140             {
00141                 // start_pos == i if we are parsing an array of templates
00142                 if (start_pos != i && !isValidTypeBasename(string(s, start_pos, i - start_pos), absolute, accept_integers))
00143                     return make_pair(false, i);
00144 
00145                 if (i + 1 == s.length())
00146                     return make_pair(false, i);
00147 
00148                 start_pos = i + 1;
00149             }
00150             else if (s[i] == ']')
00151             {
00152                 if (start_pos == i)
00153                     return make_pair(false, start_pos);
00154                 if (string(s, start_pos, i - start_pos).find_first_not_of("0123456789") != string::npos)
00155                     return make_pair(false, start_pos);
00156 
00157                 start_pos = i + 1;
00158                 if (i + 1 < s.length())
00159                 {
00160                     if (s[i + 1] == '/')
00161                         i++;
00162                     else if (s[i + 1] != '>' && s[i + 1] != '[')
00163                         return make_pair(false, i + 1);
00164                 }
00165             }
00166             else if (s[i] == '>' || s[i] == ',')
00167             {
00168                 if (!isValidTypeBasename(string(s, start_pos, i - start_pos), true, true))
00169                     return make_pair(false, i);
00170                 return make_pair(true, i);
00171             }
00172         }
00173 
00174         if (start_pos != s.length())
00175             return make_pair(isValidTypeBasename(string(s, start_pos, s.length() - start_pos), absolute, accept_integers), s.length());
00176         else return make_pair(true, s.length());
00177     }
00178 
00179     bool isValidTypename(const std::string& name, bool absolute)
00180     {
00181         if (name.empty())
00182             return false;
00183         return isValidTypename(name, 0, absolute, false).first;
00184     }
00185 
00186     bool isValidNamespace(const string& name, bool absolute)
00187     {
00188         if (name.empty()) return false;
00189         if (absolute && name[0] != NamespaceMark) return false;
00190 
00191         NameTokenizer tokenizer(name);
00192 
00193         NameTokenizer::const_iterator it = tokenizer.begin();
00194         for (; it != tokenizer.end(); ++it)
00195         {
00196             if (!isValidIdentifier(*it))
00197                 return false;
00198         }
00199 
00200         return true;
00201     }
00202 
00203     bool isInNamespace(const string& type, const std::string& nspace, bool recursive)
00204     {
00205         std::string normalized_nspace( getNormalizedNamespace(nspace) );
00206         const int   length (normalized_nspace.length());
00207 
00208         bool begins_with = string(type, 0, length) == normalized_nspace;
00209         if (!begins_with) return false;
00210         if (recursive)    return true; 
00211         std::string remainder(type, length, string::npos);
00212         return splitTypename(remainder).size() == 1;
00213     }
00214 
00215     std::string getNormalizedNamespace(const std::string& name)
00216     {
00217         if (name.empty()) return NamespaceMarkString;
00218         if (name[name.size() - 1] != NamespaceMark) return name + NamespaceMark;
00219         return name;
00220     }
00221 
00222     std::string getTypename(const std::string& name)
00223     {
00224         list<string> split = splitTypename(name);
00225         if (split.empty())
00226             return std::string();
00227         return split.back();
00228     }
00229 
00230     std::string getRelativeName(std::string const& name, std::string const& ns)
00231     {
00232         size_t size = ns.length();
00233         if (*ns.rbegin() != '/')
00234             size += 1;
00235         return std::string(name, size, string::npos);
00236     }
00237 
00238     std::string getMinimalPathTo(std::string const& full_name, std::string const& ns)
00239     {
00240         string type_ns = getNamespace(full_name);
00241         if (isInNamespace(full_name, ns, true))
00242             return getRelativeName(getNamespace(full_name), ns);
00243         else if (ns.find(type_ns) != string::npos || ns.find(full_name) != string::npos) // need an absolute path
00244             return type_ns;
00245 
00246         list<string> tok1(splitTypename(type_ns));
00247         list<string> tok2(splitTypename(ns));
00248         list<string>::const_iterator it1 = tok1.begin();
00249         list<string>::const_iterator it2 = tok2.begin();
00250         std::vector<std::string> common_tokens;
00251 
00252         // Filter out the common NS parts
00253         std::string ns1, ns2;
00254         for (; it1 != tok1.end() && it2 != tok2.end(); ++it1, ++it2)
00255         {
00256             ns1 = *it1;
00257             ns2 = *it2;
00258             int value = ns1.compare(ns2);
00259             if (value) break;
00260             common_tokens.push_back(ns1);
00261         }
00262 
00263         if (common_tokens.empty())
00264             return type_ns;
00265 
00266         // Build the remainder of both namespaces, and verify that the remainder
00267         // of the type is unambiguous. If it is, go back in it1 until it is not.
00268         // We already checked the case where the full path is ambiguous
00269         std::string result = *it1;
00270         list<string>::const_iterator remainder_it = it1;
00271         for (++remainder_it; remainder_it != tok1.end(); ++remainder_it)
00272             result += Typelib::NamespaceMarkString + *remainder_it;
00273 
00274         while (!common_tokens.empty() && ns.find(result) != string::npos)
00275         {
00276             result = common_tokens.back() + Typelib::NamespaceMarkString + result;
00277             common_tokens.pop_back();
00278         }
00279         if (common_tokens.empty())
00280             return type_ns;
00281         else if (result.empty())
00282             return result;
00283         else
00284             return result + Typelib::NamespaceMarkString;
00285     }
00286 
00287     std::string getNamespace(const std::string& name)
00288     {
00289         list<string> split = splitTypename(name);
00290         if (split.empty())
00291             return "/";
00292         split.pop_back();
00293 
00294         std::string result;
00295         for (list<string>::const_iterator it = split.begin(); it != split.end(); ++it)
00296             result += "/" + *it;
00297 
00298         result += "/";
00299         return result;
00300     }
00301 };
00302 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Mon Sep 14 2015 15:08:18