Skip to content

Commit

Permalink
Make clcpp::GetTypeNameHash constexpr so that you can use them as
Browse files Browse the repository at this point in the history
switch case values and parameterise in other ways.
  • Loading branch information
dwilliamson committed Apr 11, 2021
1 parent 5365dae commit 79dcfc4
Show file tree
Hide file tree
Showing 8 changed files with 766 additions and 320 deletions.
3 changes: 3 additions & 0 deletions inc/clcpp/clcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -983,3 +983,6 @@ namespace clcpp
return 0;
}
}

template <typename Type>
constexpr unsigned int clcppTypeHash();
174 changes: 114 additions & 60 deletions src/clReflectMerge/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,118 @@ namespace
}
}
}
}

void GenGetTypesConstexpr(CodeGen& cg, const std::vector<Primitive>& primitives, unsigned int prim_types)
{
for (size_t i = 0; i < primitives.size(); i++)
{
const Primitive& prim = primitives[i];
if ((prim.type & prim_types) != 0)
{
std::string name = NameWithGlobalScope(prim);
cg.Line("template <> constexpr unsigned int clcppTypeHash< %s >() { return 0x%x; }", name.c_str(), prim.hash);
}
}
}

void IncludeDependencies(CodeGen& cg)
{
// Include clcpp headers
cg.Line("// Generated by clmerge.exe - do not edit!");
cg.Line("#include <clcpp/clcpp.h>");
cg.Line();
}

void GenMergedCppImpl(const char* filename, const cldb::Database& db)
void ForwardDeclareTypes(CodeGen& cg, Namespace::Map& namespaces)
{
// Generate forward declarations
cg.Line("// Forward declarations for all known types");
GenNamespaceForwardDeclare(cg, &namespaces[0], true);
cg.Line();
}

void WriteFile(CodeGen& cg, const char* filename)
{
// Generate the hash for the generated code so far
unsigned int hash = cg.GenerateHash();
cg.PrefixLine("// %x", hash);

// If the output file already exists, open it and read its hash
unsigned int existing_hash = hash + 1;
FILE* fp = fopen(filename, "rb");
if (fp != 0)
{
fscanf(fp, "// %x", &existing_hash);
fclose(fp);
}

// Only write if there are changes
if (existing_hash != hash)
{
LOG(main, INFO, "Generating File: %s\n", filename);
cg.WriteToFile(filename);
}
}

void GenerateCppFile(Namespace::Map& namespaces, const std::vector<Primitive>& primitives, const char* filename)
{
CodeGen cg;

IncludeDependencies(cg);

// Generate arrays
cg.Line("// Array of type name pointers");
cg.Line("static const int clcppNbTypes = %d;", primitives.size());
cg.Line("static const clcpp::Type* clcppTypePtrs[clcppNbTypes] = { 0 };");
cg.Line();

// Generate initialisation function
cg.Line("void clcppInitGetType(const clcpp::Database* db)");
cg.EnterScope();
cg.Line("// Populate the type pointer array if a database is specified");
cg.Line("if (db != 0)");
cg.EnterScope();
for (size_t i = 0; i < primitives.size(); i++)
cg.Line("clcppTypePtrs[%d] = db->GetType(0x%x);", i, primitives[i].hash);
cg.ExitScope();
cg.ExitScope();
cg.Line();

ForwardDeclareTypes(cg, namespaces);

// Generate the implementations
cg.Line("// Specialisations for GetType and GetTypeNameHash");
cg.Line("namespace clcpp");
cg.EnterScope();
GenGetTypes(cg, primitives, PT_Type | PT_Class | PT_Struct);
cg.Line("#if defined(CLCPP_USING_MSVC)");
GenGetTypes(cg, primitives, PT_Enum);
cg.Line("#endif");
cg.ExitScope();

WriteFile(cg, filename);
}

void GenerateHFile(Namespace::Map& namespaces, const std::vector<Primitive>& primitives, const char* filename)
{
CodeGen cg;

IncludeDependencies(cg);

ForwardDeclareTypes(cg, namespaces);

// Generate the implementations
cg.Line("// Specialisations for constexpr clcppTypeHash");
GenGetTypesConstexpr(cg, primitives, PT_Type | PT_Class | PT_Struct);
cg.Line("#if defined(CLCPP_USING_MSVC)");
GenGetTypesConstexpr(cg, primitives, PT_Enum);
cg.Line("#endif");

WriteFile(cg, filename);
}
}

void GenMergedCppImpl(const char* cpp_filename, const char* h_filename, const cldb::Database& db)
{
// Build a light-weight, hierarchical representation of the incoming database
Namespace::Map namespaces;
Expand All @@ -393,67 +501,13 @@ void GenMergedCppImpl(const char* filename, const cldb::Database& db)
BuildNamespaceContents(db, namespaces, primitives);
RemoveEmptyNamespaces(&namespaces[0]);

// Include clcpp headers
CodeGen cg;
cg.Line("// Generated by clmerge.exe - do not edit!");
cg.Line("#include <clcpp/clcpp.h>");
cg.Line();

// Generate arrays
cg.Line("// Array of type name hases and pointers");
cg.Line("static const int clcppNbTypes = %d;", primitives.size());
cg.Line("static unsigned int clcppTypeNameHashes[clcppNbTypes] = { 0 };");
cg.Line("static const clcpp::Type* clcppTypePtrs[clcppNbTypes] = { 0 };");
cg.Line();

// Generate initialisation function
cg.Line("void clcppInitGetType(const clcpp::Database* db)");
cg.EnterScope();
cg.Line("// Specify hashes for all known types");
for (size_t i = 0; i < primitives.size(); i++)
cg.Line("clcppTypeNameHashes[%d] = 0x%x;", i, primitives[i].hash);
cg.Line();
cg.Line("// Populate the type pointer array if a database is specified");
cg.Line("if (db != 0)");
cg.EnterScope();
cg.Line("for (int i = 0; i < clcppNbTypes; i++)");
cg.Line("\tclcppTypePtrs[i] = db->GetType(clcppTypeNameHashes[i]);");
cg.ExitScope();
cg.ExitScope();
cg.Line();

// Generate forward declarations
cg.Line("// Forward declarations for all known types");
GenNamespaceForwardDeclare(cg, &namespaces[0], true);
cg.Line();

// Generate the implementations
cg.Line("// Specialisations for GetType and GetTypeNameHash");
cg.Line("namespace clcpp");
cg.EnterScope();
GenGetTypes(cg, primitives, PT_Type | PT_Class | PT_Struct);
cg.Line("#if defined(CLCPP_USING_MSVC)");
GenGetTypes(cg, primitives, PT_Enum);
cg.Line("#endif");
cg.ExitScope();

// Generate the hash for the generated code so far
unsigned int hash = cg.GenerateHash();
cg.PrefixLine("// %x", hash);

// If the output file already exists, open it and read its hash
unsigned int existing_hash = hash + 1;
FILE* fp = fopen(filename, "rb");
if (fp != 0)
if (cpp_filename != nullptr)
{
fscanf(fp, "// %x", &existing_hash);
fclose(fp);
GenerateCppFile(namespaces, primitives, cpp_filename);
}

// Only write if there are changes
if (existing_hash != hash)
if (h_filename != nullptr)
{
LOG(main, INFO, "Generating C++ file: %s\n", filename);
cg.WriteToFile(filename);
GenerateHFile(namespaces, primitives, h_filename);
}
}
3 changes: 1 addition & 2 deletions src/clReflectMerge/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,4 @@ class CodeGen
int m_Indent;
};


void GenMergedCppImpl(const char* filename, const cldb::Database& db);
void GenMergedCppImpl(const char* cpp_filename, const char* h_filename, const cldb::Database& db);
11 changes: 7 additions & 4 deletions src/clReflectMerge/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ int main(int argc, const char* argv[])
std::string cpp_codegen = args.GetProperty("-cpp_codegen");
if (cpp_codegen != "")
arg_start += 2;
std::string h_codegen = args.GetProperty("-h_codegen");
if (h_codegen != "")
arg_start += 2;

cldb::Database db;
cldb::Database db;
for (size_t i = arg_start; i < args.Count(); i++)
{
const char* filename = args[i].c_str();
Expand All @@ -64,8 +67,8 @@ int main(int argc, const char* argv[])
cldb::WriteTextDatabase(output_filename, db);

// Generate any required C++ code
if (cpp_codegen != "")
GenMergedCppImpl(cpp_codegen.c_str(), db);
if (cpp_codegen != "" || h_codegen != "")
GenMergedCppImpl(cpp_codegen.c_str(), h_codegen.c_str(), db);

return 0;
return 0;
}
53 changes: 53 additions & 0 deletions src/clReflectTest/TestConstexprGetType.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

#include "clcppcodegen.h"
#include <cstdio>

struct Base
{
const clcpp::Type* type = nullptr;
};

struct attrReflect FirstType : public Base
{
};

struct attrReflect SecondType : public Base
{
};

struct attrReflect ThirdType : public Base
{
};

template <typename Type>
Type* New()
{
auto* object = new Type();
object->type = clcpp::GetType<Type>();
return object;
}

void TestConstexprGetType()
{
Base* objects[] = {
New<FirstType>(),
New<SecondType>(),
New<ThirdType>(),
};

for (Base* object : objects)
{
switch (object->type->name.hash)
{
case clcppTypeHash<FirstType>():
printf("Do something with the first type\n");
break;
case clcppTypeHash<SecondType>():
printf("Do something with the second type\n");
break;
case clcppTypeHash<ThirdType>():
printf("Do something with the third type\n");
break;
}
}
}
3 changes: 2 additions & 1 deletion src/clReflectTest/clReflectTest.pibfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ config.LinkOptions.MapFile = True
cltest = CppBuild(env, [ "." ], "cltest.exe", libs, build = False)

cpp_codegen = "clcppcodegen.cpp"
h_codegen = "clcppcodegen.h"

# Generate the list of C++ files to scan - this excludes the generated C++ file
# Only add the generated C++ file to the compilation list if it's not already there
Expand All @@ -75,7 +76,7 @@ if len(scan_cpp_files) == len(cltest.cpp_files):

# Run clscan on all C++ located files, merge the result into one database and generate the C++ file
clr_scan = [ clReflect.CppScan(sys_include_paths, include_paths, [ ], env.NewFile(i)) for i in scan_cpp_files ]
clr_merge = clReflect.Merge("clRefectTest.csv", clr_scan, env.NewFile(cpp_codegen))
clr_merge = clReflect.Merge("clRefectTest.csv", clr_scan, env.NewFile(cpp_codegen), env.NewFile(h_codegen))

# Generate the exported reflection database
cpp_map_file = env.NewFile(cltest.output.GetOutputFiles(env)[1])
Expand Down
Loading

0 comments on commit 79dcfc4

Please sign in to comment.