]> granicus.if.org Git - icinga2/blobdiff - tools/mkclass/classcompiler.cpp
Implement include guards for mkclass
[icinga2] / tools / mkclass / classcompiler.cpp
index 24ddd4f72e2f8770541b18615cba1e38ce590fb3..203e90f803cd4cbb26a90d80de254380e66e81e1 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * 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;
 
@@ -51,33 +54,54 @@ size_t ClassCompiler::ReadInput(char *buffer, size_t max_size)
        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;
 
@@ -85,13 +109,44 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
        if (klass.Name.find_first_of(':') == std::string::npos)
                std::cout << "class " << klass.Name << ";" << std::endl << std::endl;
 
-       /* ReflectionTypeImpl */
+       /* TypeImpl */
        std::cout << "template<>" << std::endl
-               << "class ReflectionTypeImpl<" << klass.Name << ">"
-               << " : public ReflectionType, public Singleton<ReflectionTypeImpl<" << klass.Name << "> >" << std::endl
-               << "{" << std::endl
+               << "class TypeImpl<" << klass.Name << ">"
+               << " : 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
@@ -100,28 +155,67 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
 
        /* 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 << "ReflectionTypeImpl<" << 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
                << "\t\t" << "return ";
 
        if (!klass.Parent.empty())
-               std::cout << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
+               std::cout << "TypeImpl<" << klass.Parent << ">::StaticGetFieldId(name)";
        else
                std::cout << "-1";
 
@@ -129,38 +223,44 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                << "\t" << "}" << std::endl << std::endl;
 
        /* GetFieldInfo */
-       std::cout << "\t" << "virtual ReflectionField GetFieldInfo(int id) const" << std::endl
+       std::cout << "\t" << "virtual Field GetFieldInfo(int id) const" << std::endl
                << "\t" << "{" << std::endl
                << "\t\t" << "return StaticGetFieldInfo(id);" << std::endl
                << "\t" << "}" << std::endl << std::endl;
 
        /* StaticGetFieldInfo */
-       std::cout << "\t" << "static ReflectionField StaticGetFieldInfo(int id)" << std::endl
+       std::cout << "\t" << "static Field StaticGetFieldInfo(int id)" << std::endl
                << "\t" << "{" << std::endl;
 
        if (!klass.Parent.empty())
-               std::cout << "\t\t" << "int real_id = id - " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount();" << std::endl
-               << "\t\t" << "if (real_id < 0) { return " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldInfo(id); }" << 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 ReflectionField(" << 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;
 
@@ -176,31 +276,31 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                << "\t\t" << "return " << klass.Fields.size();
 
        if (!klass.Parent.empty())
-               std::cout << " + " << "ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
+               std::cout << " + " << "TypeImpl<" << klass.Parent << ">::StaticGetFieldCount()";
 
        std::cout << ";" << std::endl
                << "\t" << "}" << std::endl << std::endl;
 
        std::cout << "};" << std::endl << std::endl;
 
-       /* ReflectionObjectImpl */
+       /* ObjectImpl */
        std::cout << "template<>" << std::endl
-                 << "class ReflectionObjectImpl<" << klass.Name << ">"
-                 << " : public " << (klass.Parent.empty() ? "ReflectionObject" : klass.Parent) << std::endl
+                 << "class ObjectImpl<" << klass.Name << ">"
+                 << " : public " << (klass.Parent.empty() ? "Object" : klass.Parent) << std::endl
                  << "{" << std::endl
                  << "public:" << std::endl
-                 << "\t" << "DECLARE_PTR_TYPEDEFS(ReflectionObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
+                 << "\t" << "DECLARE_PTR_TYPEDEFS(ObjectImpl<" << klass.Name << ">);" << std::endl << std::endl;
 
-       /* GetType */
-       std::cout << "\t" << "virtual const ReflectionType *GetReflectionType(void) const" << std::endl
+       /* GetReflectionType */
+       std::cout << "\t" << "virtual const Type *GetReflectionType(void) const" << std::endl
                          << "\t" << "{" << std::endl
-                         << "\t\t" << "return ReflectionTypeImpl<" << klass.Name << ">::GetInstance();" << std::endl
+                         << "\t\t" << "return Type::GetByName(\"" << klass.Name << "\");" << std::endl
                          << "\t" << "}" << std::endl << std::endl;
 
        if (!klass.Fields.empty()) {
                /* constructor */
                std::cout << "public:" << std::endl
-                         << "\t" << "ReflectionObjectImpl<" << klass.Name << ">(void)" << std::endl
+                         << "\t" << "ObjectImpl<" << klass.Name << ">(void)" << std::endl
                          << "\t" << "{" << std::endl;
 
                for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) {
@@ -215,7 +315,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                                  << "\t" << "{" << std::endl;
 
                if (!klass.Parent.empty())
-                       std::cout << "\t\t" << "int real_id = id - ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
+                       std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
                                  << "\t\t" << "if (real_id < 0) { " << klass.Parent << "::SetField(id, value); return; }" << std::endl;
 
                std::cout << "\t\t" << "switch (";
@@ -227,7 +327,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
 
                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() << "(";
@@ -257,7 +357,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                                  << "\t" << "{" << std::endl;
 
                if (!klass.Parent.empty())
-                       std::cout << "\t\t" << "int real_id = id - ReflectionTypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
+                       std::cout << "\t\t" << "int real_id = id - TypeImpl<" << klass.Parent << ">::StaticGetFieldCount(); " << std::endl
                                          << "\t\t" << "if (real_id < 0) { return " << klass.Parent << "::GetField(id); }" << std::endl;
 
                std::cout << "\t\t" << "switch (";
@@ -315,7 +415,14 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                                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())
@@ -335,7 +442,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
                                          << "\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;
 
@@ -351,6 +458,18 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo& locp)
        }
 
        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)
@@ -364,16 +483,55 @@ 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/reflectionobject.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
@@ -386,4 +544,6 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream *stream)
        std::cout << "#ifdef _MSC_VER" << std::endl
                          << "#pragma warning ( pop )" << std::endl
                          << "#endif /* _MSC_VER */" << std::endl;
+
+       std::cout << "#endif /* " << guard_name << " */" << std::endl;
 }