/******************************************************************************
* Icinga 2 *
- * Copyright (C) 2012-2013 Icinga Development Team (http://www.icinga.org/) *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#include "classcompiler.h"
+#include "classcompiler.hpp"
#include <iostream>
#include <fstream>
#include <stdexcept>
+#include <map>
+#include <vector>
+#include <cstring>
using namespace icinga;
return static_cast<size_t>(m_Input->gcount());
}
-void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo& locp)
+void ClassCompiler::HandleInclude(const std::string& path, const ClassDebugInfo&)
{
std::cout << "#include \"" << path << "\"" << std::endl << std::endl;
}
-void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo& locp)
+void ClassCompiler::HandleAngleInclude(const std::string& path, const ClassDebugInfo&)
{
std::cout << "#include <" << path << ">" << std::endl << std::endl;
}
-void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo& locp)
+void ClassCompiler::HandleNamespaceBegin(const std::string& name, const ClassDebugInfo&)
{
std::cout << "namespace " << name << std::endl
<< "{" << std::endl << std::endl;
}
-void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo& locp)
+void ClassCompiler::HandleNamespaceEnd(const ClassDebugInfo&)
{
std::cout << "}" << std::endl;
}
-void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo& locp)
+void ClassCompiler::HandleCode(const std::string& code, const ClassDebugInfo&)
{
std::cout << code << std::endl;
}
-void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
+unsigned long ClassCompiler::SDBM(const std::string& str, size_t len = std::string::npos)
+{
+ unsigned long hash = 0;
+ size_t current = 0;
+
+ std::string::const_iterator it;
+
+ for (it = str.begin(); it != str.end(); it++) {
+ if (current >= len)
+ break;
+
+ char c = *it;
+
+ hash = c + (hash << 6) + (hash << 16) - hash;
+
+ current++;
+ }
+
+ return hash;
+}
+
+void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
{
std::vector<Field>::const_iterator it;
/* TypeImpl */
std::cout << "template<>" << std::endl
<< "class TypeImpl<" << klass.Name << ">"
- << " : public Type, public Singleton<TypeImpl<" << klass.Name << "> >" << std::endl
- << "{" << std::endl
+ << " : public Type";
+
+ if (!klass.TypeBase.empty())
+ std::cout << ", public " + klass.TypeBase;
+
+ std::cout << std::endl
+ << " {" << std::endl
<< "public:" << std::endl;
+ /* GetName */
+ std::cout << "\t" << "virtual String GetName(void) const" << std::endl
+ << "\t" << "{" << std::endl
+ << "\t\t" << "return \"" << klass.Name << "\";" << std::endl
+ << "\t" << "}" << std::endl << std::endl;
+
+ /* GetAttributes */
+ std::cout << "\t" << "virtual int GetAttributes(void) const" << std::endl
+ << "\t" << "{" << std::endl
+ << "\t\t" << "return " << klass.Attributes << ";" << std::endl
+ << "\t" << "}" << std::endl << std::endl;
+
+ /* GetBaseType */
+ std::cout << "\t" << "virtual const Type *GetBaseType(void) const" << std::endl
+ << "\t" << "{" << std::endl;
+
+ std::cout << "\t\t" << "return ";
+
+ if (!klass.Parent.empty())
+ std::cout << "Type::GetByName(\"" << klass.Parent << "\")";
+ else
+ std::cout << "NULL";
+
+ std::cout << ";" << std::endl
+ << "\t" << "}" << std::endl << std::endl;
+
/* GetFieldId */
std::cout << "\t" << "virtual int GetFieldId(const String& name) const" << std::endl
<< "\t" << "{" << std::endl
/* StaticGetFieldId */
std::cout << "\t" << "static int StaticGetFieldId(const String& name)" << std::endl
- << "\t" << "{" << std::endl
- << "\t\t" << "int offset = ";
+ << "\t" << "{" << std::endl;
- if (!klass.Parent.empty())
- std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
- else
- std::cout << "0";
+ if (!klass.Fields.empty()) {
+ std::cout << "\t\t" << "int offset = ";
- std::cout << ";" << std::endl << std::endl;
+ if (!klass.Parent.empty())
+ std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
+ else
+ std::cout << "0";
- int num = 0;
- for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
- std::cout << "\t\t" << "if (name == \"" << it->Name << "\")" << std::endl
- << "\t\t\t" << "return offset + " << num << ";" << std::endl;
- num++;
+ std::cout << ";" << std::endl << std::endl;
+ }
+
+ std::map<int, std::vector<std::pair<int, std::string> > > jumptable;
+
+ int hlen = 0, collisions = 0;
+
+ do {
+ int num = 0;
+
+ hlen++;
+ jumptable.clear();
+ collisions = 0;
+
+ for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
+ int hash = static_cast<int>(SDBM(it->Name, hlen));
+ jumptable[hash].push_back(std::make_pair(num, it->Name));
+ num++;
+
+ if (jumptable[hash].size() > 1)
+ collisions++;
+ }
+ } while (collisions >= 5 && hlen < 8);
+
+ if (!klass.Fields.empty()) {
+ std::cout << "\t\tswitch (static_cast<int>(Utility::SDBM(name, " << hlen << "))) {" << std::endl;
+
+ std::map<int, std::vector<std::pair<int, std::string> > >::const_iterator itj;
+
+ for (itj = jumptable.begin(); itj != jumptable.end(); itj++) {
+ std::cout << "\t\t\tcase " << itj->first << ":" << std::endl;
+
+ std::vector<std::pair<int, std::string> >::const_iterator itf;
+
+ for (itf = itj->second.begin(); itf != itj->second.end(); itf++) {
+ std::cout << "\t\t\t\t" << "if (name == \"" << itf->second << "\")" << std::endl
+ << "\t\t\t\t\t" << "return offset + " << itf->first << ";" << std::endl;
+ }
+
+ std::cout << std::endl
+ << "\t\t\t\tbreak;" << std::endl;
+ }
+
+ std::cout << "\t\t}" << std::endl;
}
std::cout << std::endl
std::cout << "\t\t" << "int real_id = id - " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount();" << std::endl
<< "\t\t" << "if (real_id < 0) { return " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldInfo(id); }" << std::endl;
- std::cout << "\t\t" << "switch (";
+ if (klass.Fields.size() > 0) {
+ std::cout << "\t\t" << "switch (";
- if (!klass.Parent.empty())
- std::cout << "real_id";
- else
- std::cout << "id";
+ if (!klass.Parent.empty())
+ std::cout << "real_id";
+ else
+ std::cout << "id";
- std::cout << ") {" << std::endl;
+ std::cout << ") {" << std::endl;
+
+ size_t num = 0;
+ for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
+ std::cout << "\t\t\t" << "case " << num << ":" << std::endl
+ << "\t\t\t\t" << "return Field(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
+ num++;
+ }
- num = 0;
- for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
- std::cout << "\t\t\t" << "case " << num << ":" << std::endl
- << "\t\t\t\t" << "return Field(" << num << ", \"" << it->Name << "\", " << it->Attributes << ");" << std::endl;
- num++;
+ std::cout << "\t\t\t" << "default:" << std::endl
+ << "\t\t";
}
- std::cout << "\t\t\t" << "default:" << std::endl
- << "\t\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl
- << "\t\t" << "}" << std::endl;
+ std::cout << "\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl;
+
+ if (klass.Fields.size() > 0)
+ std::cout << "\t\t" << "}" << std::endl;
std::cout << "\t" << "}" << std::endl << std::endl;
/* GetReflectionType */
std::cout << "\t" << "virtual const Type *GetReflectionType(void) const" << std::endl
<< "\t" << "{" << std::endl
- << "\t\t" << "return TypeImpl<" << klass.Name << ">::GetInstance();" << std::endl
+ << "\t\t" << "return Type::GetByName(\"" << klass.Name << "\");" << std::endl
<< "\t" << "}" << std::endl << std::endl;
if (!klass.Fields.empty()) {
std::cout << ") {" << std::endl;
- num = 0;
+ size_t num = 0;
for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
std::cout << "\t\t\t" << "case " << num << ":" << std::endl
<< "\t\t\t\t" << "Set" << it->GetFriendlyName() << "(";
prot = "public";
std::cout << prot << ":" << std::endl
- << "\t" << "void Set" << it->GetFriendlyName() << "(const " << it->Type << "& value)" << std::endl
+ << "\t" << "void Set" << it->GetFriendlyName() << "(";
+
+ if (it->Type == "bool" || it->Type == "double" || it->Type == "int")
+ std::cout << it->Type;
+ else
+ std::cout << "const " << it->Type << "&";
+
+ std::cout << " value)" << std::endl
<< "\t" << "{" << std::endl;
if (it->SetAccessor.empty())
<< "\t" << "{" << std::endl;
if (it->DefaultAccessor.empty())
- std::cout << "\t\t" << "return Empty;" << std::endl;
+ std::cout << "\t\t" << "return " << it->Type << "();" << std::endl;
else
std::cout << it->DefaultAccessor << std::endl;
}
std::cout << "};" << std::endl << std::endl;
+
+ /* FactoryHelper */
+ if (klass.Attributes & TAAbstract) {
+ std::cout << "template<>" << std::endl
+ << "struct FactoryHelper<" << klass.Name << ">" << std::endl
+ << "{" << std::endl
+ << "\t" << "Type::Factory GetFactory(void)" << std::endl
+ << "\t" << "{" << std::endl
+ << "\t\t" << "return Type::Factory();"
+ << "\t" << "}"
+ << "};" << std::endl << std::endl;
+ }
}
void ClassCompiler::CompileFile(const std::string& path)
return CompileStream(path, &stream);
}
+std::string ClassCompiler::BaseName(const std::string& path)
+{
+ char *dir = strdup(path.c_str());
+ std::string result;
+
+ if (dir == NULL)
+ throw std::bad_alloc();
+
+#ifndef _WIN32
+ result = basename(dir);
+#else /* _WIN32 */
+ result = PathFindFileName(dir);
+#endif /* _WIN32 */
+
+ free(dir);
+
+ return result;
+}
+
+std::string ClassCompiler::FileNameToGuardName(const std::string& fname)
+{
+ std::string result = fname;
+
+ for (int i = 0; i < result.size(); i++) {
+ result[i] = toupper(result[i]);
+
+ if (result[i] == '.')
+ result[i] = '_';
+ }
+
+ return result;
+}
+
void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
{
stream->exceptions(std::istream::badbit);
- std::cout << "#include \"base/object.h\"" << std::endl
- << "#include \"base/type.h\"" << std::endl
- << "#include \"base/singleton.h\"" << std::endl
- << "#include \"base/debug.h\"" << std::endl
- << "#include \"base/value.h\"" << std::endl
- << "#include \"base/array.h\"" << std::endl
- << "#include \"base/dictionary.h\"" << std::endl << std::endl
+ std::string guard_name = FileNameToGuardName(BaseName(path));
+
+ std::cout << "#ifndef " << guard_name << std::endl
+ << "#define " << guard_name << std::endl << std::endl;
+
+ std::cout << "#include \"base/object.hpp\"" << std::endl
+ << "#include \"base/type.hpp\"" << std::endl
+ << "#include \"base/debug.hpp\"" << std::endl
+ << "#include \"base/value.hpp\"" << std::endl
+ << "#include \"base/array.hpp\"" << std::endl
+ << "#include \"base/dictionary.hpp\"" << std::endl
+ << "#include \"base/utility.hpp\"" << std::endl << std::endl
<< "#ifdef _MSC_VER" << std::endl
<< "#pragma warning( push )" << std::endl
<< "#pragma warning( disable : 4244 )" << std::endl
std::cout << "#ifdef _MSC_VER" << std::endl
<< "#pragma warning ( pop )" << std::endl
<< "#endif /* _MSC_VER */" << std::endl;
+
+ std::cout << "#endif /* " << guard_name << " */" << std::endl;
}