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


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:22