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
00025
00026
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
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)
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
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
00267
00268
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