diff --git a/makefile b/makefile index ab342c2..bd30562 100644 --- a/makefile +++ b/makefile @@ -61,6 +61,7 @@ PLATFORM_SRCS=$(PLATFORM)/dglogging.cpp UTIL=./util UTIL_SRCS=$(UTIL)/graphanalyzer.cpp \ $(UTIL)/nodenameutils.cpp \ + $(UTIL)/processorcontainergenerator.cpp \ $(NULL) # Test Utilities diff --git a/unit-test/full/test_list.h b/unit-test/full/test_list.h index 11f22b9..df68c54 100644 --- a/unit-test/full/test_list.h +++ b/unit-test/full/test_list.h @@ -26,6 +26,7 @@ #include "test_graphstatestore.h" #include "test_graphtestutils.h" #include "test_nodenameutils.h" +#include "test_processorcontainergenerator.h" #include "test_testsplitterdetector.h" #include "test_topicstate.h" @@ -40,6 +41,7 @@ typedef int (*test_fp)(void); graphstatestore_testsuite, \ graphtestutils_testsuite, \ nodenameutils_testsuite, \ + processorcontainergenerator_testsuite, \ testsplitterdetector_testsuite, \ topicstate_testsuite, \ } diff --git a/unit-test/full/test_processorcontainergenerator.cpp b/unit-test/full/test_processorcontainergenerator.cpp new file mode 100644 index 0000000..d8ae8a3 --- /dev/null +++ b/unit-test/full/test_processorcontainergenerator.cpp @@ -0,0 +1,126 @@ +// Copyright 2017 Nest Labs, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "nltest.h" +#include "errortype.hpp" + +#include "test_processorcontainergenerator.h" + +#include "processorcontainergenerator.hpp" +#include "graph.hpp" +#include "detector.hpp" +#include "nodenameutils.hpp" + +#include +#include +#include + +#define HPP_DIR "tmptest/cpp/" + +#define SUITE_DECLARATION(name, test_ptr) { #name, test_ptr, setup_##name, teardown_##name } + +using namespace DetectorGraph; + +static int setup_processorcontainergenerator(void *inContext) +{ + int r; + + r = system("mkdir -p " HPP_DIR); + + return r; +} + +static int teardown_processorcontainergenerator(void *inContext) +{ + int r = 0; + + r = system("rm -fR " HPP_DIR "*"); + + return r; +} + +// TODO(DGRAPH-3): do actual stuff here. +static void Test_EmptyGraph(nlTestSuite *inSuite, void *inContext) +{ + Graph graph; + ProcessorContainerGenerator processorContainerGenerator(graph); + processorContainerGenerator.GenerateClass(HPP_DIR "emptygraph.hpp"); +} + +struct TestTopicStateA : public DetectorGraph::TopicState {}; +struct TestTopicStateB : public DetectorGraph::TopicState {}; +class TestDetectorA : public DetectorGraph::Detector +, public SubscriberInterface +, public Publisher +{ +public: + TestDetectorA(Graph* graph) + : DetectorGraph::Detector(graph) + { + Subscribe(this); + SetupPublishing(this); + } + + void Evaluate(const TestTopicStateA& aTestTopicStateA) + { + + Publisher::Publish(TestTopicStateB()); + } +}; + +// TODO(DGRAPH-3): TEST actual stuff here. +static void Test_GetVertexMeta(nlTestSuite *inSuite, void *inContext) +{ + Graph graph; + TestDetectorA detectorA(&graph); + + ProcessorContainerGenerator processorContainerGenerator(graph); + processorContainerGenerator.SetStringFilter(&NodeNameUtils::GetDemangledName); + std::vector vertices = processorContainerGenerator.GetVerticesData(); + + for (unsigned i = 0; i < vertices.size(); i++) + { + const ProcessorContainerGenerator::VertexMeta& vertexMeta = vertices[i]; + printf("Vertex %d, Type %d, Class=%s, Instance=%s\n", i, int(vertexMeta.type), + vertexMeta.className.c_str(), vertexMeta.instanceName.c_str()); + } +} + +// TODO(DGRAPH-3): TEST actual stuff here. +static void Test_SingleDetector(nlTestSuite *inSuite, void *inContext) +{ + Graph graph; + TestDetectorA detectorA(&graph); + + ProcessorContainerGenerator processorContainerGenerator(graph); + processorContainerGenerator.SetStringFilter(&NodeNameUtils::GetDemangledName); + processorcontainergenerator.SetOutputClassName("TestAGraph"); + processorContainerGenerator.GenerateClass(HPP_DIR "singledetector.hpp"); +} + +static const nlTest sTests[] = { + NL_TEST_DEF("Test_EmptyGraph", Test_EmptyGraph), + NL_TEST_DEF("Test_GetVertexMeta", Test_GetVertexMeta), + NL_TEST_DEF("Test_SingleDetector", Test_SingleDetector), + NL_TEST_SENTINEL() +}; + +//This function creates the Suite (i.e: the name of your test and points to the array of test functions) +extern "C" +int processorcontainergenerator_testsuite(void) +{ + nlTestSuite theSuite = SUITE_DECLARATION(processorcontainergenerator, &sTests[0]); + nlTestRunner(&theSuite, NULL); + return nlTestRunnerStats(&theSuite); +} diff --git a/unit-test/full/test_processorcontainergenerator.h b/unit-test/full/test_processorcontainergenerator.h new file mode 100644 index 0000000..caf4eea --- /dev/null +++ b/unit-test/full/test_processorcontainergenerator.h @@ -0,0 +1,30 @@ +/* + * Copyright 2017 Nest Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DETECTORGRAPH_UNIT_TEST_PROCESSORCONTAINERGENERATOR_H_ +#define DETECTORGRAPH_UNIT_TEST_PROCESSORCONTAINERGENERATOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + int processorcontainergenerator_testsuite(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/util/processorcontainergenerator.cpp b/util/processorcontainergenerator.cpp new file mode 100644 index 0000000..db4a831 --- /dev/null +++ b/util/processorcontainergenerator.cpp @@ -0,0 +1,178 @@ +// Copyright 2017 Nest Labs, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "processorcontainergenerator.hpp" + +#include +#include +#include +#include +#include + +#include "dglogging.hpp" + +namespace DetectorGraph +{ + +ProcessorContainerGenerator::ProcessorContainerGenerator(Graph& aGraph) +: mGraph(aGraph) +, mStringFilter(NULL) +, mProcessorContainerName("GeneratedProcessorContainer") +{ +} + +void ProcessorContainerGenerator::SetStringFilter(std::string (*aStringFilter)(const std::string&)) +{ + mStringFilter = aStringFilter; +} + +void ProcessorContainerGenerator::SetOutputClassName(const std::string& aClassName) +{ + mProcessorContainerName = aClassName; +} + +std::vector ProcessorContainerGenerator::GetVerticesData() +{ + std::vector vertexMetaVector; + DetectorGraph::ErrorType r; + r = mGraph.TopoSortGraph(); + if (r != DetectorGraph::ErrorType_Success) + { + DG_LOG("Failed to get graph's Topological Sort."); + DG_ASSERT(false); + } + + for (std::list< Vertex* >::const_iterator vertexIt = mGraph.GetVertices().begin(); + vertexIt != mGraph.GetVertices().end(); + ++vertexIt) + { + const Vertex* vertex = (*vertexIt); + VertexMeta vertexMetadata; + vertexMetadata.className = GetClassName(vertex->GetName()); + vertexMetadata.type = vertex->GetVertexType(); + vertexMetadata.instanceName = GetInstanceName(vertexMetadata.className, vertexMetadata.type); + + vertexMetaVector.push_back(vertexMetadata); + } + + return vertexMetaVector; +} + +void ProcessorContainerGenerator::GenerateClass(const std::string& aOutFilePath) +{ + ofstream cppHeaderFile; + cppHeaderFile.open(aOutFilePath.c_str()); + + if (cppHeaderFile.is_open()) + { + std::vector vertices = GetVerticesData(); + + cppHeaderFile << "#include \"graph.hpp\"" << endl; + cppHeaderFile << "#include \"detector.hpp\"" << endl; + cppHeaderFile << "#include \"processorcontainer.hpp\"" << endl; + + cppHeaderFile << endl; + + cppHeaderFile << "class " << mProcessorContainerName << " : public DetectorGraph::ProcessorContainer" << endl; + cppHeaderFile << "{" << endl; + cppHeaderFile << "public:" << endl; + cppHeaderFile << " " << mProcessorContainerName << "()" << endl; + + for (unsigned nodeIndex = 0; nodeIndex < vertices.size(); nodeIndex++) + { + if (nodeIndex == 0) + { + cppHeaderFile << " : "; + } + else + { + cppHeaderFile << " , "; + } + + if (vertices[nodeIndex].type == DetectorGraph::Vertex::kDetectorVertex) + { + cppHeaderFile << vertices[nodeIndex].instanceName << "(&mGraph)" << endl; + } + else if (vertices[nodeIndex].type == DetectorGraph::Vertex::kTopicVertex) + { + cppHeaderFile << vertices[nodeIndex].instanceName << "(mGraph.ResolveTopic<"; + cppHeaderFile << vertices[nodeIndex].className << ">())" << endl; + } + } + cppHeaderFile << " {" << endl; + cppHeaderFile << " }" << endl; + + for (unsigned nodeIndex = 0; nodeIndex < vertices.size(); nodeIndex++) + { + if (vertices[nodeIndex].type == DetectorGraph::Vertex::kDetectorVertex) + { + cppHeaderFile << " " << vertices[nodeIndex].className << " "; + cppHeaderFile << vertices[nodeIndex].instanceName << ";" << endl; + } + else if (vertices[nodeIndex].type == DetectorGraph::Vertex::kTopicVertex) + { + cppHeaderFile << " " << vertices[nodeIndex].className << "* "; + cppHeaderFile << vertices[nodeIndex].instanceName << ";" << endl; + } + } + cppHeaderFile << "};" << endl; + + cppHeaderFile.close(); + + DG_LOG("Sorted DetectorGraph::ProcessorContainer header file created at: %s", aOutFilePath.c_str()); + } +} + +std::string ProcessorContainerGenerator::GetClassName(const char* aCompilerName) const +{ + std::string retString = std::string(aCompilerName); + if (mStringFilter) + { + retString = mStringFilter(retString); + } + + return retString; +} + +std::string ProcessorContainerGenerator::GetInstanceName(const std::string& aClassName, DetectorGraph::Vertex::VertexType type) const +{ + std::string instanceName = aClassName; + + std::string::size_type lastNamespaceDelimiterPos; + lastNamespaceDelimiterPos = instanceName.rfind("::"); + if (lastNamespaceDelimiterPos != std::string::npos) + { + lastNamespaceDelimiterPos += 2; // "::".size() + instanceName.erase(0, lastNamespaceDelimiterPos); + } + + if (type == DetectorGraph::Vertex::kDetectorVertex) + { + return "m" + instanceName; + } + else if (type == DetectorGraph::Vertex::kTopicVertex) + { + instanceName.erase(0, 6); // "Topic<".size() + instanceName.erase(instanceName.size()-1, 1); // ">" + instanceName.append("Topic"); + return "mp" + instanceName; + } + else + { + return instanceName; + } +} + + +} diff --git a/util/processorcontainergenerator.hpp b/util/processorcontainergenerator.hpp new file mode 100644 index 0000000..a885da6 --- /dev/null +++ b/util/processorcontainergenerator.hpp @@ -0,0 +1,79 @@ +// Copyright 2017 Nest Labs, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef DETECTORGRAPH_UTIL_PROCESSORCONTAINERGENERATOR_HPP_ +#define DETECTORGRAPH_UTIL_PROCESSORCONTAINERGENERATOR_HPP_ + + +#include "graph.hpp" + +#include +#include +#include + +namespace DetectorGraph +{ + +using namespace std; + +/** + * @brief Class that provides debugging/diagnostics to a DetectorGraph detector graph + * + * This is just an early prototype. + * + * TODO(DGRAPH-3): + * - Add Lite vs. Full style options + * - Add Generate Topics bool? + * - Upstream Lite TopicContainer API. + */ +class ProcessorContainerGenerator +{ +public: + struct VertexMeta + { + std::string className; + std::string instanceName; + DetectorGraph::Vertex::VertexType type; + }; + + ProcessorContainerGenerator(Graph& aGraph); + + /** + * @brief Sets a string-filter to cleanup compiler-generated names + * (through typeid(*this).name()). + */ + void SetStringFilter(std::string (*aStringFilter)(const std::string&)); + + void SetOutputClassName(const std::string& aClassName); + + /** + * @brief Print a C++ header for an ordered ProcessContainer + */ + void GenerateClass(const std::string& aOutFilePath); + + std::vector GetVerticesData(); + +private: + std::string GetClassName(const char* aCompilerName) const; + std::string GetInstanceName(const std::string& aNodeName, DetectorGraph::Vertex::VertexType type) const; + +private: + Graph& mGraph; + std::string (*mStringFilter)(const std::string&); + std::string mProcessorContainerName; +}; + +} + +#endif // DETECTORGRAPH_UTIL_PROCESSORCONTAINERGENERATOR_HPP_