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
00022
00023
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
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)
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
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
00264
00265
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