瀏覽代碼

changed modules and base processor

Willi Zschiebsch 4 年之前
父節點
當前提交
fb7ccd8148
共有 55 個文件被更改,包括 7675 次插入1161 次删除
  1. 14 11
      lib/CMakeLists.txt
  2. 2 19
      lib/include/Generator.h
  3. 0 19
      lib/include/HandlerModule.h
  4. 4 1
      lib/include/IConnection.h
  5. 1 1
      lib/include/IGenerator.h
  6. 3 8
      lib/include/IInput.h
  7. 20 0
      lib/include/IInteractive.h
  8. 0 4
      lib/include/IListener.h
  9. 12 0
      lib/include/IManager.h
  10. 24 19
      lib/include/IModule.h
  11. 3 1
      lib/include/IOptimizable.h
  12. 4 8
      lib/include/IOutput.h
  13. 13 12
      lib/include/IProcessor.h
  14. 0 5
      lib/include/IType.h
  15. 4 2
      lib/include/IUnique.h
  16. 8 8
      lib/include/Input.h
  17. 22 35
      lib/include/ModuleBase.h
  18. 0 18
      lib/include/ModuleMerge.h
  19. 0 16
      lib/include/ModuleParameter.h
  20. 0 28
      lib/include/ModuleSQL.h
  21. 0 13
      lib/include/ModuleSwitch.h
  22. 5 6
      lib/include/Output.h
  23. 34 50
      lib/include/ProcessorBase.h
  24. 0 0
      lib/include/ProcessorEvolution.h
  25. 0 39
      lib/include/ProcessorStandard.h
  26. 29 0
      lib/include/Registration.h
  27. 0 24
      lib/src/Generator.cpp
  28. 18 8
      lib/src/Input.cpp
  29. 50 153
      lib/src/ModuleBase.cpp
  30. 98 73
      lib/src/ModuleHTTP.cpp
  31. 56 255
      lib/src/ModuleMath.cpp
  32. 54 12
      lib/src/ModuleMerge.cpp
  33. 49 4
      lib/src/ModuleParameter.cpp
  34. 97 51
      lib/src/ModuleSQL.cpp
  35. 57 7
      lib/src/ModuleSwitch.cpp
  36. 23 9
      lib/src/Output.cpp
  37. 193 210
      lib/src/ProcessorBase.cpp
  38. 0 0
      lib/src/ProcessorEvolution.cpp
  39. 107 23
      lib/src/ProcessorStandard.cpp
  40. 38 0
      lib/src/Registration.cpp
  41. 2 0
      lib/test/CMakeLists.txt
  42. 0 0
      lib/test/test_Input.cpp
  43. 26 9
      lib/test/test_ModuleMath.cpp
  44. 14 0
      lib/test/test_Output.cpp
  45. 179 0
      thirdparty/googletest/BUILD.bazel
  46. 37 0
      thirdparty/googletest/ci/build-linux-bazel.sh
  47. 2 0
      thirdparty/googletest/ci/build-platformio.sh
  48. 49 0
      thirdparty/googletest/ci/install-linux.sh
  49. 40 0
      thirdparty/googletest/ci/install-osx.sh
  50. 5 0
      thirdparty/googletest/ci/install-platformio.sh
  51. 1985 0
      thirdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h
  52. 888 0
      thirdparty/googletest/googlemock/src/gmock-spec-builders.cc
  53. 110 0
      thirdparty/googletest/googlemock/test/BUILD.bazel
  54. 2775 0
      thirdparty/googletest/googlemock/test/gmock-spec-builders_test.cc
  55. 521 0
      thirdparty/googletest/googletest/test/BUILD.bazel

+ 14 - 11
lib/CMakeLists.txt

@@ -1,13 +1,14 @@
 cmake_minimum_required(VERSION 3.8.0)
 cmake_minimum_required(VERSION 3.8.0)
 project(mdd_lib)
 project(mdd_lib)
 
 
-add_library(${PROJECT_NAME} SHARED
+add_library(${PROJECT_NAME} STATIC
 	include/Connector.h
 	include/Connector.h
 	include/Generator.h
 	include/Generator.h
-        include/HandlerModule
 	include/IConnection.h
 	include/IConnection.h
 	include/IGenerator.h
 	include/IGenerator.h
         include/IInput.h
         include/IInput.h
+        include/IInteractive.h
+        include/IManager.h
         include/IModule.h
         include/IModule.h
         include/Input.h
         include/Input.h
 	include/IOptimizable.h
 	include/IOptimizable.h
@@ -17,21 +18,14 @@ add_library(${PROJECT_NAME} SHARED
 	include/IState.h
 	include/IState.h
         include/IUnique.h
         include/IUnique.h
         include/ModuleBase.h
         include/ModuleBase.h
-	include/ModuleMerge.h
-	include/ModuleParameter.h
-	include/ModuleSplitt.h
-        include/ModuleSQL.h
-        include/ModuleSwitch.h
 	include/OptimizerBase.h
 	include/OptimizerBase.h
 	include/OptimizerEvolutionary.h
 	include/OptimizerEvolutionary.h
         include/Output.h
         include/Output.h
         include/ProcessorBase.h
         include/ProcessorBase.h
-        include/ProcessorEvolution.h
-	include/ProcessorStandard.h
+	include/Registration.h
 	include/state.h
 	include/state.h
 
 
 	src/Connector.cpp
 	src/Connector.cpp
-	src/Generator.cpp
         src/Input.cpp
         src/Input.cpp
         src/ModuleBase.cpp
         src/ModuleBase.cpp
         src/ModuleHTTP.cpp
         src/ModuleHTTP.cpp
@@ -45,8 +39,8 @@ add_library(${PROJECT_NAME} SHARED
 	src/OptimizerEvolutionary.cpp
 	src/OptimizerEvolutionary.cpp
         src/Output.cpp
         src/Output.cpp
         src/ProcessorBase.cpp
         src/ProcessorBase.cpp
-	src/ProcessorEvolution.cpp
         src/ProcessorStandard.cpp
         src/ProcessorStandard.cpp
+	src/Registration.cpp
         )
         )
 
 
 target_include_directories(${PROJECT_NAME} PUBLIC
 target_include_directories(${PROJECT_NAME} PUBLIC
@@ -67,11 +61,20 @@ install(DIRECTORY include DESTINATION .)
 install(TARGETS ${PROJECT_NAME} DESTINATION lib/$<CONFIG> EXPORT targets)
 install(TARGETS ${PROJECT_NAME} DESTINATION lib/$<CONFIG> EXPORT targets)
 install(EXPORT targets DESTINATION cmake)
 install(EXPORT targets DESTINATION cmake)
 
 
+#[[
+
 add_custom_command(TARGET mdd_lib POST_BUILD
 add_custom_command(TARGET mdd_lib POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E copy
     COMMAND ${CMAKE_COMMAND} -E copy
 	"$<TARGET_FILE:mdd_lib>"
 	"$<TARGET_FILE:mdd_lib>"
 	"${CMAKE_BINARY_DIR}/lib/test/$<CONFIGURATION>")
 	"${CMAKE_BINARY_DIR}/lib/test/$<CONFIGURATION>")
 
 
+add_custom_command(TARGET mdd_lib POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy
+	"$<TARGET_FILE:mdd_lib>"
+	"${CMAKE_BINARY_DIR}/lib/test")
+
+]]
+
 
 
 if(${TESTS_ENABLED})
 if(${TESTS_ENABLED})
     add_subdirectory(test)
     add_subdirectory(test)

+ 2 - 19
lib/include/Generator.h

@@ -1,5 +1,3 @@
-
-
 #pragma once
 #pragma once
 
 
 #include <map>
 #include <map>
@@ -13,26 +11,11 @@ namespace mdd
 		: public IGenerator
 		: public IGenerator
 	{
 	{
 
 
-		virtual std::shared_ptr<IModule> Generate()
+		virtual std::shared_ptr<IModule> generate()
 		{
 		{
 			return std::make_shared<MODULE_CLASS>();
 			return std::make_shared<MODULE_CLASS>();
 		}
 		}
 	};
 	};
-
-	std::map<std::string, std::shared_ptr<IGenerator>>&
-		GetGenerators(
-			const std::string& name = "", 
-			const std::shared_ptr<IGenerator>& generator = nullptr);
-
-	template<class MODULE_CLASS>
-	class GeneratorRegistration
-	{
-	public:
-		GeneratorRegistration(const std::string& name)
-		{
-			GetGenerators(name, std::make_shared<Generator<MODULE_CLASS>>());
-		}
-	};
 }
 }
 
 
-#define ADD_GENERATOR(CLASS) namespace{mdd::GeneratorRegistration<CLASS> reg_sdewfdsf(#CLASS);}
+//#define ADD_GENERATOR(CLASS) namespace{mdd::GeneratorRegistration<CLASS> reg_sdewfdsf(#CLASS);}

+ 0 - 19
lib/include/HandlerModule.h

@@ -1,19 +0,0 @@
-#ifndef MDD_HANDLERMODULE_H
-#define MDD_HANDLERMODULE_H
-#include <string>
-#include <IModule.h>
-
-namespace mdd{
-    template<class T>
-    class HandlerModule{
-    public:
-        std::shared_ptr<IModule> moduleHandler;
-        std::shared_ptr<T> accessHandler;
-        HandlerModule(std::shared_ptr<IModule> module, std::shared_ptr<T> access){
-            moduleHandler = module;
-            accessHandler = access;
-        }
-    };
-}
-
-#endif //MDD_MODULEHANDLER_H

+ 4 - 1
lib/include/IConnection.h

@@ -3,14 +3,17 @@
 
 
 #include <vector>
 #include <vector>
 #include <memory>
 #include <memory>
+#include "IUnique.h"
 
 
 namespace mdd {
 namespace mdd {
 	template <class T>
 	template <class T>
-	class IConnection {
+	class IConnection
+	{
 	public:
 	public:
 		virtual int addConnection(std::shared_ptr<T> conector) = 0;
 		virtual int addConnection(std::shared_ptr<T> conector) = 0;
 		virtual int removeConnection(std::shared_ptr<T> conector) = 0;
 		virtual int removeConnection(std::shared_ptr<T> conector) = 0;
 		virtual bool connect(std::shared_ptr<T> conector) = 0;
 		virtual bool connect(std::shared_ptr<T> conector) = 0;
+		virtual void disconnect() = 0;
 		virtual ~IConnection() {};
 		virtual ~IConnection() {};
 	};
 	};
 }
 }

+ 1 - 1
lib/include/IGenerator.h

@@ -11,6 +11,6 @@ namespace mdd
 	public:
 	public:
 		virtual ~IGenerator() {}
 		virtual ~IGenerator() {}
 
 
-		virtual std::shared_ptr<IModule> Generate() = 0;
+		virtual std::shared_ptr<IModule> generate() = 0;
 	};
 	};
 }
 }

+ 3 - 8
lib/include/IInput.h

@@ -3,11 +3,8 @@
 
 
 //#include "json.hpp"
 //#include "json.hpp"
 #include <memory>
 #include <memory>
+#include "IInteractive.h"
 #include "IOutput.h"
 #include "IOutput.h"
-#include "IUnique.h"
-#include "IState.h"
-#include "IConnection.h"
-#include "IOptimizable.h"
 #include <vector>
 #include <vector>
 
 
 namespace mdd{
 namespace mdd{
@@ -20,12 +17,10 @@ namespace mdd{
     };
     };
 
 
     class IInput 
     class IInput 
-        : public IUnique
-        , public IState
-        , public IConnection<IOutput>
-        , public IOptimizable
+        : public IInteractive<IOutput>  
     {
     {
     public:
     public:
+        typedef std::shared_ptr<IInput> Ptr;
         virtual const limits& getLimits() = 0;
         virtual const limits& getLimits() = 0;
         virtual limits& setLimits() = 0;
         virtual limits& setLimits() = 0;
         virtual std::shared_ptr<IOutput> getConnection() = 0;
         virtual std::shared_ptr<IOutput> getConnection() = 0;

+ 20 - 0
lib/include/IInteractive.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include <memory>
+#include "IUnique.h"
+#include "IState.h"
+#include "IConnection.h"
+#include "IOptimizable.h"
+
+namespace mdd {
+    template <class T>
+    class IInteractive
+        : public IState
+        , public IConnection<T>
+        , public IOptimizable
+    {
+    public:
+        typedef std::shared_ptr<IInteractive> Ptr;
+        virtual std::string getParentID() = 0;
+    };
+}

+ 0 - 4
lib/include/IListener.h

@@ -1,4 +0,0 @@
-#ifndef MDD_ILISTENER_H
-#define MDD_ILISTENER_H
-
-#endif //MDD_ILISTENER_H

+ 12 - 0
lib/include/IManager.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <json.hpp>
+namespace mdd {
+	class IManager {
+	public:
+		virtual bool configure(const std::string& config) = 0;
+		virtual std::string getBaseConfiguration() = 0;
+		//virtual std::string getGeneratorID() = 0;
+		virtual void load(const json& json) = 0;
+		virtual json dump() = 0;
+	};
+}

+ 24 - 19
lib/include/IModule.h

@@ -3,36 +3,41 @@
 
 
 #include "IOutput.h"
 #include "IOutput.h"
 #include "IInput.h"
 #include "IInput.h"
+#include "IManager.h"
 #include "state.h"
 #include "state.h"
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 #include <memory>
 #include <memory>
 
 
 namespace mdd {
 namespace mdd {
-    class IOutput;
-
-    class IModule : public IUnique{
+    class IModule 
+        : public IUnique
+        , public IManager
+    {
     public:
     public:
         typedef std::shared_ptr<IModule> Ptr;
         typedef std::shared_ptr<IModule> Ptr;
 
 
-        virtual void updateID() = 0;
-        virtual std::vector<std::string> getInputs() = 0;
-        virtual std::vector<std::string> getOutputs() = 0;
-        virtual std::vector<std::string> getInputIDs() = 0;
-        virtual std::vector<std::string> getOutputIDs() = 0;
-        virtual std::vector<state> getInputStates() = 0;
-        virtual std::vector<state> getOutputStates() = 0;
-        virtual std::shared_ptr<IOutput> getOutput(const std::string& output_id) = 0;
-        virtual std::shared_ptr<IInput> getInput(const std::string& input_id) = 0;
-        virtual std::vector <std::shared_ptr<IOutput>> getInputConnections() = 0;
-        virtual std::vector <std::vector <std::shared_ptr<IInput>>> getOutputConnections() = 0;
-        virtual std::vector <std::shared_ptr<IInput>> getOptimizableInputs() = 0;
-        virtual std::vector <std::shared_ptr<IOutput>> getOptimizableOutputs() = 0;
+        virtual size_t getNumInputs() = 0;
+        virtual size_t getNumOutputs() = 0;
+        //"Processor1/Math1/Value1"
+        //Proc2/MAth1;Value1
+        //Proc2->get(MAth1;Value1)
+
+        //MAth1;Value1
+        //MAth1->get(Value1)
+        //Value1
+        virtual std::shared_ptr<IInput> getInput(const std::string& id) = 0;
+        virtual std::shared_ptr<IInput> getInput(size_t index) = 0;
+        virtual std::shared_ptr<IOutput> getOutput(const std::string& id) = 0;
+        virtual std::shared_ptr<IOutput> getOutput(size_t index) = 0;
+
+
+        //virtual std::vector <std::vector <std::shared_ptr<IInput>>> getConnectionsOf(Input) = 0;
+        //virtual std::vector <std::shared_ptr<IInput>> getOptimizable() = 0;
+
         virtual state update() = 0;
         virtual state update() = 0;
+        virtual void disconnect() = 0;
         virtual ~IModule() = default;
         virtual ~IModule() = default;
-
-        virtual bool configure(const std::string& config) = 0;
-        virtual std::string getBaseConfiguration() = 0;
     };
     };
 }
 }
 #endif //MDD_IMODULE_H
 #endif //MDD_IMODULE_H

+ 3 - 1
lib/include/IOptimizable.h

@@ -2,9 +2,11 @@
 #define IOPTIMIZABLE_H
 #define IOPTIMIZABLE_H
 
 
 #include <vector>
 #include <vector>
+#include "IUnique.h"
 
 
 namespace mdd {
 namespace mdd {
-	class IOptimizable {
+	class IOptimizable : public IUnique
+	{
 	public:
 	public:
 		virtual const std::vector<double>& getValue() = 0;
 		virtual const std::vector<double>& getValue() = 0;
 		virtual std::vector<double>& setValue() = 0;
 		virtual std::vector<double>& setValue() = 0;

+ 4 - 8
lib/include/IOutput.h

@@ -2,11 +2,9 @@
 #define MDD_IOUTPUT_H
 #define MDD_IOUTPUT_H
 #include "json.hpp"
 #include "json.hpp"
 #include <memory>
 #include <memory>
-#include "IUnique.h"
-#include "IState.h"
+#include "IInteractive.h"
 //#include "IInput.h"
 //#include "IInput.h"
-#include "IOptimizable.h"
-#include "IConnection.h"
+
 
 
 namespace mdd
 namespace mdd
 {
 {
@@ -14,12 +12,10 @@ namespace mdd
     class IModule;
     class IModule;
 
 
     class IOutput 
     class IOutput 
-        : public IUnique
-        , public IState
-        , public IConnection<IInput>
-        , public IOptimizable
+        : public IInteractive<IInput>
     {
     {
     public:
     public:
+        typedef std::shared_ptr<IOutput> Ptr;
         virtual std::vector<std::shared_ptr<IInput>> getConnections() = 0;
         virtual std::vector<std::shared_ptr<IInput>> getConnections() = 0;
         virtual ~IOutput() = default;
         virtual ~IOutput() = default;
     };
     };

+ 13 - 12
lib/include/IProcessor.h

@@ -1,23 +1,24 @@
-#ifndef MDD_IPROCESSOR_H
-#define MDD_IPROCESSOR_H
+#pragma once
 
 
 #include "IModule.h"
 #include "IModule.h"
+#include "ModuleParameter.cpp"
 #include <vector>
 #include <vector>
 
 
 namespace mdd
 namespace mdd
 {
 {
     class IProcessor: public  IModule{
     class IProcessor: public  IModule{
     public:
     public:
-        virtual std::string  addModule(std::shared_ptr<IModule> module) = 0;
-        virtual std::string addModuleInput(std::string module_ID, std::string input_ID) = 0;
-        virtual std::string addModuleInput(std::shared_ptr<IModule> module, std::shared_ptr<IInput> input) = 0;
-        virtual std::string addModuleOutput(std::string module_ID, std::string output_ID) = 0;
-        virtual std::string addModuleOutput(std::shared_ptr<IModule> module, std::shared_ptr<IOutput> output) = 0;
+        virtual std::string addModule(std::shared_ptr<IModule> module) = 0;
         virtual void  removeModule(std::shared_ptr<IModule> module) = 0;
         virtual void  removeModule(std::shared_ptr<IModule> module) = 0;
-        virtual std::vector<std::string> getModules() = 0;
-        virtual std::vector<std::string> getModuleIDs() = 0;
-        virtual std::shared_ptr<IModule> getModule(std::string module_id) = 0;
+
+        virtual std::vector<std::shared_ptr<ModuleParameter>>& getInputParams() = 0;
+        virtual std::vector<std::shared_ptr<ModuleParameter>>& getOutputParams() = 0;
+
+        virtual std::vector<std::shared_ptr<IModule >>& getModules() = 0;
+ 
+        virtual size_t getNumModuls() = 0;
+        virtual std::shared_ptr<IModule> getModule(size_t index) = 0;
+        virtual std::shared_ptr<IModule> getModule(const std::string& id) = 0;
+        virtual bool connect(const std::string& output_id, const std::vector<std::string>& input_ids) = 0;
     };
     };
 }
 }
-
-#endif //MDD_IPROCESSOR_H

+ 0 - 5
lib/include/IType.h

@@ -1,5 +0,0 @@
-#ifndef MDD_ITYPE_H
-#define MDD_ITYPE_H
-
-
-#endif //MDD_ITYPE_H

+ 4 - 2
lib/include/IUnique.h

@@ -7,9 +7,11 @@ namespace mdd{
     public:
     public:
         virtual std::string setType(const std::string& type) = 0;
         virtual std::string setType(const std::string& type) = 0;
         virtual std::string getType() = 0;
         virtual std::string getType() = 0;
-        virtual std::string getID() = 0;
-        virtual std::string setPrefix(const std::string& prefix) = 0;
+        
         virtual std::string setAppendix(int appendix) = 0;
         virtual std::string setAppendix(int appendix) = 0;
+        virtual int getAppendix() = 0;
+
+        virtual std::string getID() = 0;
     };
     };
 }
 }
 #endif
 #endif

+ 8 - 8
lib/include/Input.h

@@ -4,33 +4,32 @@
 #include <string>
 #include <string>
 #include <functional>
 #include <functional>
 #include "IInput.h"
 #include "IInput.h"
-#include "IOutput.h"
+#include "IModule.h"
 #include <memory>
 #include <memory>
 #include "IUnique.h"
 #include "IUnique.h"
 
 
 namespace mdd {
 namespace mdd {
     class Input : public IInput{
     class Input : public IInput{
     private:
     private:
-        std::string _prefix;
         std::string _type;
         std::string _type;
         int _appendix;
         int _appendix;
+        IModule* _parent;
 
 
         std::vector<double> _value;
         std::vector<double> _value;
         //std::function<bool(const json &)> _verification;
         //std::function<bool(const json &)> _verification;
         std::shared_ptr <IOutput> _output;
         std::shared_ptr <IOutput> _output;
         bool _optimizable;
         bool _optimizable;
-        limits _limit;
-    protected:
-       
-
+        limits _limit;//make shared_ptr!!!
     public:
     public:
-        Input(const std::string &type, int appendix, const std::vector<double>& default_value);
+        Input(IModule* parent, const std::string &type, int appendix, const std::vector<double>& default_value);
         //const std::function<bool(const json &)> &verification = [](const json&) { return true; }
         //const std::function<bool(const json &)> &verification = [](const json&) { return true; }
         std::string setType(const std::string& type) override;
         std::string setType(const std::string& type) override;
         std::string getType() override;
         std::string getType() override;
         std::string getID() override;
         std::string getID() override;
-        std::string setPrefix(const std::string& prefix) override;
         std::string setAppendix(int appendix) override;
         std::string setAppendix(int appendix) override;
+        int getAppendix() override;
+
+        std::string getParentID() override;
 
 
         state getState() override;
         state getState() override;
         void resetState() override;
         void resetState() override;
@@ -50,6 +49,7 @@ namespace mdd {
         int addConnection(std::shared_ptr<IOutput> output) override;
         int addConnection(std::shared_ptr<IOutput> output) override;
         int removeConnection(std::shared_ptr<IOutput> output) override;
         int removeConnection(std::shared_ptr<IOutput> output) override;
         bool connect(std::shared_ptr<IOutput> output) override;
         bool connect(std::shared_ptr<IOutput> output) override;
+        void disconnect() override;
     };
     };
 }
 }
 
 

+ 22 - 35
lib/include/ModuleBase.h

@@ -8,54 +8,41 @@
 
 
 namespace mdd {
 namespace mdd {
 
 
-class ModuleBase : public  IModule{
+    class ModuleBase : public  IModule{
     private:
     private:
-        std::string _prefix = "";
         std::string _type = "";
         std::string _type = "";
-        std::string _base_config = "";
         int _appendix = 0;
         int _appendix = 0;
-        std::vector<std::shared_ptr<Input>> _inputs;
-        std::vector<std::shared_ptr<Output>> _outputs;
-
-    protected:
-        ModuleBase(const std::string& base_config = "{}");
 
 
-        virtual bool configure(const std::string& config) {return true;};
-        virtual std::string getBaseConfiguration();
+        std::string _base_config = "";
 
 
-        std::shared_ptr<IOutput> getOutput(int handle);
-        std::shared_ptr<IInput> getInput(int handle);
-        int addInput(const std::string& type, const std::vector<double>& value);
-        int addOutput(const std::string& type, const std::vector<double>& initial);
+    protected:
+        ModuleBase(const std::string& base_config = "{}"); 
 
 
-        int pop_backInput();
-        int pop_backOutput();
+        std::vector<std::shared_ptr<Input>> inputs;
+        std::vector<std::shared_ptr<Output>> outputs;
 
 
-        int clearInput();
-        int clearOutput();
+    public:
+        bool configure(const std::string& config) { return true; };
+        std::string getBaseConfiguration();
 
 
-        int eraseInput(int index);
-        int eraseOutput(int index);
+        size_t getNumInputs() override;
+        size_t getNumOutputs() override;
 
 
-    public:
-        std::vector<std::string> getInputs() override;
-        std::vector<std::string> getInputIDs() override;
-        std::vector<std::string> getOutputs() override;
-        std::vector<std::string> getOutputIDs() override;
-        std::vector<state> getInputStates() override;
-        std::vector<state> getOutputStates() override;
-        std::vector<std::shared_ptr<IOutput>> getInputConnections() override;
-        std::vector <std::vector <std::shared_ptr<IInput>>> getOutputConnections() override;
-        std::vector <std::shared_ptr<IInput>> getOptimizableInputs() override;
-        std::vector <std::shared_ptr<IOutput>> getOptimizableOutputs() override;
-        std::shared_ptr<IOutput> getOutput(const std::string& output_id) override;
-        std::shared_ptr<IInput> getInput(const std::string& input_id) override;
+        std::shared_ptr<IInput> getInput(size_t index) override;
+        std::shared_ptr<IInput> getInput(const std::string& id) override;
+        std::shared_ptr<IOutput> getOutput(size_t index) override;
+        std::shared_ptr<IOutput> getOutput(const std::string& id) override;
+        
         std::string setType(const std::string& type) override;
         std::string setType(const std::string& type) override;
         std::string getType() override;
         std::string getType() override;
         std::string getID() override;
         std::string getID() override;
-        std::string setPrefix(const std::string& prefix) override;
         std::string setAppendix(int appendix) override;
         std::string setAppendix(int appendix) override;
-        void updateID() override ;
+        int getAppendix() override;
+    
+        void load(const json& j) override;
+        json dump() override;
+
+        void disconnect() override;
     };
     };
 }
 }
 #endif //MDD_BASEMODULE_H
 #endif //MDD_BASEMODULE_H

+ 0 - 18
lib/include/ModuleMerge.h

@@ -1,18 +0,0 @@
-#ifndef MODULEMERGE_H
-#define MODULEMERGE_H
-#include "ModuleBase.h"
-
-namespace mdd {
-	class ModuleMerge : public ModuleBase {
-	private:
-
-	public:
-		ModuleMerge();
-		int addModuleInput();
-		int removeModuleInput();
-		std::string setInputType(const std::string& input_id, const std::string& new_type);
-		state update() override;
-	};
-}
-
-#endif 

+ 0 - 16
lib/include/ModuleParameter.h

@@ -1,16 +0,0 @@
-#ifndef MODULEPARAMETER_H
-#define MODULEPARAMETER_H
-#include "ModuleBase.h"
-
-namespace mdd {
-
-    class ModuleParameter : public ModuleBase {
-    private:
-       
-    public:
-        ModuleParameter();
-        state update() override;
-    };
-}
-
-#endif

+ 0 - 28
lib/include/ModuleSQL.h

@@ -1,28 +0,0 @@
-#ifndef MDD_MODULESQL_H
-#define MDD_MODULESQL_H
-#include "ModuleBase.h"
-#include <iostream>
-#include <string>
-#include <sqlite3.h>
-
-namespace mdd {
-	class ModuleSQL : public ModuleBase {
-	private:
-		sqlite3* _db;
-		std::string _tbname;
-		void erase_keyword(std::string& str, std::string key);
-		struct _entity {
-			std::string key;
-			std::string type;
-		};
-		std::vector<_entity> _content;
-
-	public:
-		ModuleSQL(std::string dbname);
-		~ModuleSQL();
-		state update() override;
-	};
-}
-
-
-#endif

+ 0 - 13
lib/include/ModuleSwitch.h

@@ -1,13 +0,0 @@
-#ifndef MDD_MODULESWITCH_H
-#define MDD_MODULESWITCH_H
-
-#include "ModuleBase.h"
-
-namespace mdd{
-    class ModuleSwitch : public ModuleBase{
-    public:
-        ModuleSwitch();
-        state update() override;
-    };
-}
-#endif //MDD_MODULESWITCH_H

+ 5 - 6
lib/include/Output.h

@@ -1,7 +1,6 @@
 #ifndef MDD_OUTPUT_H
 #ifndef MDD_OUTPUT_H
 #define MDD_OUTPUT_H
 #define MDD_OUTPUT_H
 #include "IOutput.h"
 #include "IOutput.h"
-#include "IInput.h"
 #include "IModule.h"
 #include "IModule.h"
 
 
 namespace mdd {
 namespace mdd {
@@ -9,16 +8,14 @@ namespace mdd {
     private:
     private:
         state _state;
         state _state;
         std::vector<double> _value;
         std::vector<double> _value;
-        std::string _prefix;
         std::string _type;
         std::string _type;
         int _appendix;
         int _appendix;
         std::vector<std::shared_ptr<IInput>> _connections;
         std::vector<std::shared_ptr<IInput>> _connections;
         bool _optimizable;
         bool _optimizable;
-
-    protected:
+        IModule* _parent;
 
 
     public:
     public:
-        Output(const std::string& type, int appendix, const std::vector<double>& initial);
+        Output(IModule* parent, const std::string& type, int appendix, const std::vector<double>& initial);
         const std::vector<double>& getValue() override;
         const std::vector<double>& getValue() override;
         std::vector<double>& setValue() override;
         std::vector<double>& setValue() override;
         state setValue(const std::vector<double>& val) override;
         state setValue(const std::vector<double>& val) override;
@@ -29,12 +26,14 @@ namespace mdd {
         std::string setType(const std::string& type) override;
         std::string setType(const std::string& type) override;
         std::string getType() override;
         std::string getType() override;
         std::string getID() override;
         std::string getID() override;
-        std::string setPrefix(const std::string& prefix) override;
         std::string setAppendix(int appendix) override;
         std::string setAppendix(int appendix) override;
+        int getAppendix() override;
+        std::string getParentID() override;
         int addConnection(std::shared_ptr<IInput> input) override;
         int addConnection(std::shared_ptr<IInput> input) override;
         int removeConnection(std::shared_ptr<IInput> input) override;
         int removeConnection(std::shared_ptr<IInput> input) override;
         bool connect(std::shared_ptr<IInput> input) override;
         bool connect(std::shared_ptr<IInput> input) override;
         std::vector<std::shared_ptr<IInput>> getConnections() override;
         std::vector<std::shared_ptr<IInput>> getConnections() override;
+        void disconnect() override;
     };
     };
 }
 }
 #endif
 #endif

+ 34 - 50
lib/include/ProcessorBase.h

@@ -5,75 +5,59 @@
 #include "Input.h"
 #include "Input.h"
 #include "Output.h"
 #include "Output.h"
 #include "IProcessor.h"
 #include "IProcessor.h"
+#include "Registration.h"
 
 
 namespace mdd {
 namespace mdd {
+    class Registration;
     class ProcessorBase : public IProcessor{
     class ProcessorBase : public IProcessor{
     private:
     private:
 
 
-        template<class T>
-        class HandlerModule {
-        public:
-            std::shared_ptr<IModule> moduleHandler;
-            std::shared_ptr<T> accessHandler;
-            HandlerModule(std::shared_ptr<IModule> module, std::shared_ptr<T> access) {
-                moduleHandler = module;
-                accessHandler = access;
-            }
-        };
-
-        std::string _prefix = "";
         std::string _type = "";
         std::string _type = "";
         int _appendix = 0;
         int _appendix = 0;
-
-        std::vector<std::shared_ptr<Input>> _processor_inputs;
-        std::vector<std::shared_ptr<Output>> _processor_outputs;
-
-        std::vector<HandlerModule<IInput>> _module_inputs;
-        std::vector<HandlerModule<IOutput>> _module_outputs;
-        std::vector<std::shared_ptr<IModule>> _modules;
+        std::string _base_config = "";
 
 
     protected:
     protected:
-        int addProcesorInput(const std::string& type, const std::vector<double>& value);
-        int addProcessorOutput(const std::string& type, const std::vector<double>& initial);
-        std::shared_ptr<IOutput> getProcessorOutput(int handle);
-        std::shared_ptr<IInput> getProcessorInput(int handle);
-        std::shared_ptr<IModule> getModule(int handle);
+        ProcessorBase(const std::string& base_config);
+
+        std::vector<std::shared_ptr<Input>>processor_inputs;
+        std::vector<std::shared_ptr<Output>> processor_outputs;
+        std::vector<std::shared_ptr<IModule>> modules;
+        std::vector<std::shared_ptr<ModuleParameter>> inputs;
+        std::vector<std::shared_ptr<ModuleParameter>> outputs;
 
 
     public:
     public:
+        bool configure(const std::string& config) { return true; };
+        std::string getBaseConfiguration() override;
+
         std::string getID() override ;
         std::string getID() override ;
         std::string setType(const std::string& type) override;
         std::string setType(const std::string& type) override;
         std::string getType() override;
         std::string getType() override;
-        std::string setPrefix(const std::string& prefix) override;
+        
         std::string setAppendix(int appendix) override;
         std::string setAppendix(int appendix) override;
-        void updateID() override ;
+        int getAppendix() override;
 
 
         std::string addModule(std::shared_ptr<IModule> module) override ;
         std::string addModule(std::shared_ptr<IModule> module) override ;
         void removeModule(std::shared_ptr<IModule> module) override;
         void removeModule(std::shared_ptr<IModule> module) override;
-        std::string addModuleInput(std::string module_ID, std::string input_ID) override;
-        std::string addModuleInput(std::shared_ptr<IModule> module, std::shared_ptr<IInput> input) override;
-        std::string addModuleOutput(std::string module_ID, std::string output_ID) override;
-        std::string addModuleOutput(std::shared_ptr<IModule> module, std::shared_ptr<IOutput> output) override;
-
-        std::vector<std::string> getInputs() override;
-        std::vector<std::string> getOutputs() override;
-        std::vector<std::string> getModules() override;
-
-        std::vector<std::string> getInputIDs() override;
-        std::vector<std::string> getOutputIDs() override;
-        std::vector<std::string> getModuleIDs() override;
-
-        std::vector<state> getInputStates() override;
-        std::vector<state> getOutputStates() override;
-
-        std::vector<std::shared_ptr<IOutput>> getInputConnections() override;
-        std::vector <std::vector <std::shared_ptr<IInput>>> getOutputConnections() override;
-
-        std::vector <std::shared_ptr<IInput>> getOptimizableInputs() override;
-        std::vector <std::shared_ptr<IOutput>> getOptimizableOutputs() override;
 
 
-        std::shared_ptr<IOutput> getOutput(const std::string& output_id) override;
-        std::shared_ptr<IInput> getInput(const std::string& input_id) override;
-        std::shared_ptr<IModule> getModule(std::string module_id) override;
+        std::vector<std::shared_ptr<ModuleParameter>>& getInputParams() override;
+        std::vector<std::shared_ptr<ModuleParameter>>& getOutputParams() override;
+
+        size_t getNumInputs() override;
+        size_t getNumOutputs() override;
+        std::shared_ptr<IInput> getInput(const std::string& id) override;
+        std::shared_ptr<IInput> getInput(size_t index) override;
+        std::shared_ptr<IOutput> getOutput(const std::string& id) override;
+        std::shared_ptr<IOutput> getOutput(size_t index) override;
+        
+        std::vector<std::shared_ptr<IModule >>& getModules();
+        size_t getNumModuls() override;
+        std::shared_ptr<IModule> getModule(size_t index) override;
+        std::shared_ptr<IModule> getModule(const std::string& id) override;
+
+        bool connect(const std::string& output_id, const std::vector<std::string>& input_ids);
+        void disconnect() override;
+        void load(const json& j) override;
+        json dump() override;
     };
     };
 }
 }
 #endif
 #endif

+ 0 - 0
lib/include/ProcessorEvolution.h


+ 0 - 39
lib/include/ProcessorStandard.h

@@ -1,39 +0,0 @@
-#ifndef MDD_PROCESSORSTANDARD_H
-#define MDD_PROCESSORSTANDARD_H
-#include "ProcessorBase.h"
-#include "Output.h"
-#include <chrono>
-namespace mdd {
-    enum priority {
-        MANUAL,
-        STATIC,
-        DYNAMIC,
-        TIME
-    };
-
-    class ProcessorStandard : public ProcessorBase {
-    private:
-        struct module_priority{
-            std::shared_ptr<IModule> module_ptr;
-            size_t inputCounter;
-            size_t changeCounter;
-            size_t outputCounter;
-            int time_priority;
-            module_priority(std::shared_ptr<IModule> module, size_t inputs = 0, size_t outputs = 0, size_t change = 0);
-        };
-        std::vector<module_priority> _priority_list;
-
-    public:
-        int maxIterations;
-        priority priorityEvaluation;
-
-        ProcessorStandard(priority priorityEvaluation = MANUAL, int maxIterations = -1);
-        std::string addModule(std::shared_ptr<IModule> module) override;
-        void removeModule(std::shared_ptr<IModule> module) override;
-        std::vector<std::shared_ptr<IModule>> getModulePriority();
-        state update() override;
-        std::shared_ptr<IOutput> getIteration();
-    };
-}
-
-#endif //MDD_PROCESSORMANUAL_H

+ 29 - 0
lib/include/Registration.h

@@ -0,0 +1,29 @@
+#pragma once
+#include <mutex>
+#include <map>
+#include <memory>
+#include <IGenerator.h>
+
+#define REGISTER(CLASS) registerGenerator<CLASS>(#CLASS);
+
+namespace mdd {
+	class Registration {
+	private:
+		std::map<std::string, std::shared_ptr<IGenerator>> _gens;
+		//std::mutex _mutex;
+	public:
+		template<class MODULE_CLASS>
+		void registerGenerator(const std::string& name) {
+			auto generator = std::make_shared<Generator<MODULE_CLASS>>();
+			if (generator != nullptr)
+			{
+				//_mutex.lock();
+				_gens[name] = generator;
+				//_mutex.unlock();
+			}
+		}
+		Registration();
+		IModule::Ptr generateModule(const std::string& name);
+	};
+}
+

+ 0 - 24
lib/src/Generator.cpp

@@ -1,24 +0,0 @@
-
-
-#include <Generator.h>
-#include <mutex>
-namespace mdd
-{
-
-	std::map<std::string, std::shared_ptr<IGenerator>>&
-		GetGenerators(
-			const std::string& name,
-			const std::shared_ptr<IGenerator>& generator)
-	{
-		static std::map<std::string, std::shared_ptr<IGenerator>> gens;
-		static std::mutex mutex;
-
-		if (generator != nullptr)
-		{
-			mutex.lock();
-			gens[name] = generator;
-			mutex.unlock();
-		}
-		return gens;
-	}
-}

+ 18 - 8
lib/src/Input.cpp

@@ -11,10 +11,10 @@ namespace mdd{
         _output = nullptr;
         _output = nullptr;
         return 0;
         return 0;
     }
     }
-    Input::Input(const std::string& type, int appendix, const std::vector<double>& default_value) {
+    Input::Input(IModule* parent, const std::string& type, int appendix, const std::vector<double>& default_value) {
+        _parent = parent;
         _type = type;
         _type = type;
         _value = default_value;
         _value = default_value;
-        _prefix = "";
         _appendix = appendix;
         _appendix = appendix;
         _optimizable = false;
         _optimizable = false;
 
 
@@ -28,12 +28,7 @@ namespace mdd{
         return  _type;
         return  _type;
     }
     }
     std::string Input::getID(){
     std::string Input::getID(){
-        return _prefix + "/" + _type + std::to_string(_appendix);
-    }
-
-    std::string Input::setPrefix(const std::string& prefix){
-        _prefix = prefix;
-        return getID();
+        return _type + std::to_string(_appendix);
     }
     }
 
 
     std::string Input::setAppendix(int appendix){
     std::string Input::setAppendix(int appendix){
@@ -41,6 +36,14 @@ namespace mdd{
         return  getID();
         return  getID();
     }
     }
 
 
+    int Input::getAppendix() {
+        return _appendix;
+    }
+
+    std::string Input::getParentID() {
+        return _parent->getID();
+    }
+
     state Input::getState() {
     state Input::getState() {
         if (_output == nullptr) {
         if (_output == nullptr) {
             return state::UNCHANGED;
             return state::UNCHANGED;
@@ -85,6 +88,13 @@ namespace mdd{
         return true;
         return true;
     }
     }
 
 
+    void Input::disconnect() {
+        if (_output != nullptr)
+        {
+            _output->removeConnection(std::make_shared<Input>((*this)));
+        }
+    }
+
     bool Input::isOptimizable() {
     bool Input::isOptimizable() {
         return _optimizable;
         return _optimizable;
     }
     }

+ 50 - 153
lib/src/ModuleBase.cpp

@@ -3,127 +3,52 @@
 
 
 namespace mdd {
 namespace mdd {
 
 
+    size_t ModuleBase::getNumInputs(){
+        return inputs.size();
+    }
+
+    size_t ModuleBase::getNumOutputs() {
+        return outputs.size();
+    }
+
     std::string ModuleBase::setType(const std::string& type){
     std::string ModuleBase::setType(const std::string& type){
         _type=type;
         _type=type;
-        updateID();
         return getID();
         return getID();
     }
     }
     std::string ModuleBase::getType(){
     std::string ModuleBase::getType(){
         return _type;
         return _type;
     }
     }
 
 
-    std::vector<std::string> ModuleBase::getInputs() {
-        std::vector<std::string> ret;
-        for (auto &input  : _inputs) {
-            ret.push_back(input->getType());
-        }
-        return ret;
-    }
-
-    std::vector<std::string> ModuleBase::getInputIDs(){
-        std::vector<std::string> ret;
-        for (auto &input  : _inputs) {
-            ret.push_back(input->getID());
-        }
-        return ret;
-    }
-
-    std::vector<std::string> ModuleBase::getOutputs() {
-        std::vector<std::string> ret;
-        for (auto &output  : _outputs) {
-            ret.push_back(output->getType());
-        }
-        return ret;
-    }
-
-    std::vector<std::string> ModuleBase::getOutputIDs(){
-        std::vector<std::string> ret;
-        for (auto &output  : _outputs) {
-            ret.push_back(output->getID());
-        }
-        return ret;
-    }
-
-    std::vector<state> ModuleBase::getInputStates() {
-        std::vector<state> ret;
-        for (auto& input : _inputs) {
-            ret.push_back(input->getState());
-        }
-        return ret;
-    }
-
-    std::vector<state> ModuleBase::getOutputStates() {
-        std::vector<state> ret;
-        for (auto& output : _outputs) {
-            ret.push_back(output->getState());
-        }
-        return ret;
-    }
-
-    std::vector<std::shared_ptr<IOutput>> ModuleBase::getInputConnections()
-    {
-        std::vector<std::shared_ptr<IOutput>> ret;
-        for (auto& input : _inputs) {
-            ret.push_back(input->getConnection());
-        }
-        return ret;
-    }
 
 
-    int ModuleBase::addInput(const std::string& type , const std::vector<double>& value) {
-        _inputs.emplace_back(std::make_shared<Input>(type, _inputs.size(), value));
-        _inputs.back()->setPrefix(getID());
-        return _inputs.size() - 1;
-    }
-
-
-    std::vector<std::vector<std::shared_ptr<IInput>>> ModuleBase::getOutputConnections()
-    {
-        std::vector<std::vector<std::shared_ptr<IInput>>> ret;
-        for (auto& output : _outputs) {
-            ret.push_back(output->getConnections());
-        }
-        return ret;
-    }
-
-    std::vector<std::shared_ptr<IInput>> ModuleBase::getOptimizableInputs()
-    {
-        std::vector<std::shared_ptr<IInput>> ret;
-        for (auto it = _inputs.begin(); it != _inputs.end();  ++it)
+    std::shared_ptr<IInput> ModuleBase::getInput(size_t index) {
+        if (index <= inputs.size())
         {
         {
-            if ((*it)->isOptimizable())
-            {
-                ret.push_back((*it));
-            }
+            return inputs[index];
         }
         }
-        return ret;
+        return nullptr;
     }
     }
 
 
-    std::vector<std::shared_ptr<IOutput>> ModuleBase::getOptimizableOutputs()
-    {
-        std::vector<std::shared_ptr<IOutput>> ret;
-        for (auto it = _outputs.begin(); it != _outputs.end(); ++it)
-        {
-            if ((*it)->isOptimizable())
-            {
-                ret.push_back((*it));
+    std::shared_ptr<IInput> ModuleBase::getInput(const std::string& input_id){
+        for(auto& input : inputs){
+            if (input->getID() == input_id) {
+                return input;
             }
             }
         }
         }
-        return ret;
+        return nullptr;
     }
     }
 
 
-    std::shared_ptr<IOutput> ModuleBase::getOutput(const std::string& output_id) {
-        for(auto& output : _outputs){
-                if (output->getID() == output_id) {
-                    return output;
-                }
+    std::shared_ptr<IOutput> ModuleBase::getOutput(size_t index) {
+        if (index <= outputs.size())
+        {
+            return outputs[index];
         }
         }
         return nullptr;
         return nullptr;
     }
     }
 
 
-    std::shared_ptr<IInput> ModuleBase::getInput(const std::string& input_id){
-        for(auto& input : _inputs){
-            if (input->getID() == input_id) {
-                return input;
+    std::shared_ptr<IOutput> ModuleBase::getOutput(const std::string& output_id) {
+        for (auto& output : outputs) {
+            if (output->getID() == output_id) {
+                return output;
             }
             }
         }
         }
         return nullptr;
         return nullptr;
@@ -140,71 +65,43 @@ namespace mdd {
         return _base_config;
         return _base_config;
     }
     }
 
 
-    std::shared_ptr<IOutput> ModuleBase::getOutput(int handle) {
-        return _outputs[handle];
-    }
-
-    std::shared_ptr<IInput> ModuleBase::getInput(int handle){
-        return _inputs[handle];
-    }
-
-    int ModuleBase::addOutput(const std::string& type, const std::vector<double>& initial) {
-        _outputs.push_back(std::make_shared<Output>( type, _outputs.size(), initial));
-        _outputs.back()->setPrefix(getID());
-        return  _outputs.size()-1;
-    }
-
-    int ModuleBase::pop_backInput(){
-        _inputs.pop_back();
-        return _inputs.size();
-    }
-    int ModuleBase::pop_backOutput(){
-        _outputs.pop_back();
-        return _outputs.size();
+    std::string ModuleBase::getID(){
+        return _type + std::to_string(_appendix);
     }
     }
 
 
-    int ModuleBase::clearInput(){
-        _inputs.clear();
-        return _inputs.size();
-    }
-    int ModuleBase::clearOutput(){
-        _outputs.clear();
-        return _outputs.size();
+    std::string ModuleBase::setAppendix(int appendix){
+        _appendix = appendix;
+        return getID();
     }
     }
 
 
-    int ModuleBase::eraseInput(int index){
-        _inputs.erase(_inputs.begin()+index);
-        return _inputs.size();
-    }
-    int ModuleBase::eraseOutput(int index){
-        _outputs.erase(_outputs.begin()+index);
-        return _outputs.size();
+    int ModuleBase::getAppendix() {
+        return _appendix;
     }
     }
 
 
-    std::string ModuleBase::getID(){
-        return _prefix + "/" + _type + std::to_string(_appendix);
+    void ModuleBase::load(const json& j)
+    {
+        if (j.contains("configure"))
+        {
+            configure(j["configure"].get<std::string>());
+        }
     }
     }
+    json ModuleBase::dump()
+    {
+        json ret;
 
 
+        ret["configure"] = _base_config;
 
 
-    std::string ModuleBase::setPrefix(const std::string& prefix){
-        _prefix = prefix;
-        updateID();
-        return getID();
-    }
-
-    std::string ModuleBase::setAppendix(int appendix){
-        _appendix = appendix;
-        updateID();
-        return getID();
+        return ret;
     }
     }
 
 
-    void ModuleBase::updateID(){
-        std::string new_prefix =  getID();
-        for (auto &input  : _inputs){
-            input->setPrefix(new_prefix);
+    void ModuleBase::disconnect() {
+        for (size_t i = 0; i < inputs.size(); i++)
+        {
+            inputs[i]->disconnect();
         }
         }
-        for (auto &output  : _outputs){
-            output->setPrefix(new_prefix);
+        for (size_t i = 0; i < outputs.size(); i++)
+        {
+            outputs[i]->disconnect();
         }
         }
     }
     }
 }
 }

+ 98 - 73
lib/src/ModuleHTTP.cpp

@@ -5,12 +5,12 @@
 #include <boost/process.hpp>
 #include <boost/process.hpp>
 #include <filesystem>
 #include <filesystem>
 
 
-//#include <wait.h>
-
+//#include <wait.h
 #include "ModuleBase.h"
 #include "ModuleBase.h"
 #include <httplib.h>
 #include <httplib.h>
 #include <memory>
 #include <memory>
 #include <chrono>
 #include <chrono>
+#include "IOptimizable.h"
 
 
 using namespace httplib;
 using namespace httplib;
 namespace mdd{
 namespace mdd{
@@ -26,14 +26,17 @@ namespace mdd{
     protected:
     protected:
         bool connect();
         bool connect();
         std::string str_to_json(const std::string& input);
         std::string str_to_json(const std::string& input);
+
+        template<class T>
+        state updateVectorOf(std::vector<std::shared_ptr<T>>& vec, const std::string& msg);;
         state updateInputs();
         state updateInputs();
         state updateOutputs();
         state updateOutputs();
-        void updateLayout();
 
 
     public:
     public:
         ModuleHTTP();// std::string fname, std::string id, int port);
         ModuleHTTP();// std::string fname, std::string id, int port);
         ~ModuleHTTP();
         ~ModuleHTTP();
         state update() override;
         state update() override;
+        bool configure(const std::string& config) override;
     };
     };
 
 
     bool ModuleHTTP::connect(){
     bool ModuleHTTP::connect(){
@@ -75,102 +78,126 @@ namespace mdd{
         return str;
         return str;
     }
     }
 
 
-    state ModuleHTTP::updateInputs() {
-        Client cli(_id, _port);
-
-        std::string body;
-        auto res = cli.Get("/inputs",
-                           [&](const char *data, size_t data_length) {
-                               body.append(data, data_length);
-                               return true;
-                           });
-        assert(res->body.empty());
-        body =  std::string(R"()") + body;
-        json inputs = json::parse(body.c_str());
-
-        for(int j = 0; j < (int)getInputs().size()-(int)inputs.size(); ++j){
-            pop_backInput();
+    template<class T>
+    state ModuleHTTP::updateVectorOf(std::vector<std::shared_ptr<T>>& vec, const std::string& msg) {
+        
+        json server = json::parse(msg.c_str());
+        int diff =  (int)server.size() - (int)vec.size();
+        if (diff < 0)
+        {
+            vec.erase(vec.end() + diff, vec.end());
         }
         }
-        for(size_t i=0; i < getInputs().size(); i++){
-            getInput(i)->setType(inputs[i]["type"].get<std::string>());
-            getInput(i)->setAppendix(i);
-            getInput(i)->setValue() = inputs[i]["value"].get<std::vector<double>>();
+        for(size_t i=0; i < vec.size(); i++){
+            vec[i]->setType(server[i]["type"].get<std::string>());
+            vec[i]->setAppendix(i);
+            vec[i]->setValue() = server[i]["value"].get<std::vector<double>>();
         }
         }
-        for(int index = getInputs().size(); index < inputs.size(); ++index){
-            if (inputs[index]["value"].is_array())
+        for (size_t i = 0; i < diff; i++)
+        {
+            size_t length = vec.size();
+            if (server[length]["value"].is_array())
             {
             {
-                addInput(inputs[index]["type"].get<std::string>(), inputs[index]["value"].get<std::vector<double>>());
+                vec.emplace_back(server[length]["type"].get<std::string>(), length, server_inputs[length]["value"].get<std::vector<double>>());
             }
             }
             else {
             else {
-                addInput(inputs[index]["type"].get<std::string>(), { inputs[index]["value"].get<double>() });
+                vec.emplace_back(server[length]["type"].get<std::string>(), length, std::vector<double>{server_inputs[length]["value"].get<double>()});
                 std::cout << "Warning: Server expects single values, but mdd work with arrays!" << std::endl;
                 std::cout << "Warning: Server expects single values, but mdd work with arrays!" << std::endl;
             }
             }
         }
         }
         return state::UNCHANGED;
         return state::UNCHANGED;
     }
     }
+    state ModuleHTTP::updateInputs() {
+        Client cli(_id, _port);
 
 
+        std::string body;
+        auto res = cli.Get("/inputs",
+            [&](const char* data, size_t data_length) {
+            body.append(data, data_length);
+            return true;
+        });
+        assert(res->body.empty());
+        body = std::string(R"()") + body;
+        updateVectorOf(inputs, body);
+    }
     state ModuleHTTP::updateOutputs() {
     state ModuleHTTP::updateOutputs() {
         Client cli(_id, _port);
         Client cli(_id, _port);
 
 
         std::string body;
         std::string body;
         auto res = cli.Get("/outputs",
         auto res = cli.Get("/outputs",
-                           [&](const char *data, size_t data_length) {
-                               body.append(data, data_length);
-                               return true;
-                           });
+            [&](const char* data, size_t data_length) {
+            body.append(data, data_length);
+            return true;
+        });
 
 
         assert(res->body.empty());
         assert(res->body.empty());
-        body =  std::string(R"()") + body;
-        json outputs = json::parse(body);
-        state output_state = state::UNCHANGED;
-        for(int j = 0; j < (int)getOutputs().size()-(int)outputs.size(); ++j){
-            pop_backOutput();
-            output_state = state::CHANGED;
-        }
-        for(size_t i=0; i < getOutputs().size(); i++){
-            //getOutput(i)->setType(outputs[i]["type"].get<std::string>());
-            //getOutput(i)->setAppendix(i);
-            getOutput(i)->setValue(outputs[i]["value"].get<std::vector<double>>());
-        }
-        for(int index = getOutputs().size(); index < outputs.size(); ++index){
-            if (outputs[index]["value"].is_array()) {
-                addOutput(outputs[index]["type"].get<std::string>(), outputs[index]["value"].get<std::vector<double>>());
-            }
-            else
-            {
-                addOutput(outputs[index]["type"].get<std::string>(), { outputs[index]["value"].get<double>() });
-                std::cout << "Warning: Server delivers single values, but mdd work with arrays!" << std::endl;
-            }
-            output_state = state::CHANGED;
-        }
-        return output_state;
-    }
-
-    void ModuleHTTP::updateLayout(){
-        updateInputs();
-        updateOutputs();
+        body = std::string(R"()") + body;
+        updateVectorOf(outputs, body);
     }
     }
 
 
     ModuleHTTP::ModuleHTTP()// std::string fname, std::string id, int port):
     ModuleHTTP::ModuleHTTP()// std::string fname, std::string id, int port):
-      //  _fname(fname),
-       // _id(id),
-       // _port(port)
+        : ModuleBase(R"JSON(
+        [{
+            "name":"url",
+            "value":""
+        },{
+            "name":"port",
+            "value":256
+        },{
+            "name":"file",
+            "value":""
+        }])JSON")
     {
     {
-       /* setType("HTTP");
+        setType("HTTP");
+    }
 
 
-        if(!fname.empty()){
-            if (std::filesystem::exists(fname))
+    bool ModuleHTTP::configure(const std::string& config) {
+        json config_parsed = json::parse(config);
+        bool found = false;
+        for (size_t i = 0; i < config_parsed.size(); i++)
+        {
+            if (config_parsed[i].contains("name"))
             {
             {
-                _child = std::make_unique<child>("python3 " + fname + " " + std::to_string(port));
+                if (config_parsed[i]["name"].get<std::string>() == "url")
+                {
+                    _id = config_parsed[i]["value"].get<std::string>();
+                    found = true;
+                }
+                else if (config_parsed[i]["name"].get<std::string>() == "port")
+                {
+                    _port = config_parsed[i]["value"].get<int>();
+                    found = true;
+                }
+                else if (config_parsed[i]["name"].get<std::string>() == "file")
+                {
+                    _fname = config_parsed[i]["value"].get<std::string>();
+                    found = true;
+                }
+                else {
+                    std::cout << "ERROR Configure option: " << config_parsed[i]["name"].dump() << " do not exist!" << std::endl;
+                    return false;
+                }
             }
             }
             else {
             else {
-                std::cout << "ERROR Couldnt find: " << fname << std::endl;
+                std::cout << "ERROR Wrong configure format: " << config_parsed[i].dump() << std::endl;
+                return false;
             }
             }
         }
         }
-        while(!connect()){
+        if (!_fname.empty()) {
+            if (std::filesystem::exists(_fname))
+            {
+                _child = std::make_unique<child>("python3 " + _fname + " " + std::to_string(_port));
+            }
+            else {
+                std::cout << "ERROR Couldnt find: " << _fname << std::endl;
+                return false;
+            }
+        }
+        while (!connect()) {
             std::this_thread::sleep_for(std::chrono::microseconds(500));
             std::this_thread::sleep_for(std::chrono::microseconds(500));
         }
         }
-        updateLayout();*/
+        updateInputs();
+        updateOutputs();
+        return found;
     }
     }
 
 
     ModuleHTTP::~ModuleHTTP()
     ModuleHTTP::~ModuleHTTP()
@@ -185,7 +212,7 @@ namespace mdd{
     state ModuleHTTP::update() {
     state ModuleHTTP::update() {
         Client cli(_id, _port);
         Client cli(_id, _port);
         json new_inputs;
         json new_inputs;
-        for (int i = 0; i < getInputs().size(); ++i) {
+        for (int i = 0; i < inputs.size(); ++i) {
             json input;
             json input;
             input["value"] = getInput(i)->getValue();
             input["value"] = getInput(i)->getValue();
             //std::cout << "ModuleHTTP::update: last: " << getInput(i)->getValue().back() << std::endl;
             //std::cout << "ModuleHTTP::update: last: " << getInput(i)->getValue().back() << std::endl;
@@ -207,6 +234,4 @@ namespace mdd{
         return updateOutputs();
         return updateOutputs();
     }
     }
 
 
-}
-
-ADD_GENERATOR(mdd::ModuleHTTP);
+}

+ 56 - 255
lib/src/ModuleMath.cpp

@@ -7,302 +7,103 @@
 namespace mdd {
 namespace mdd {
 
 
     class ModuleMath : public ModuleBase {
     class ModuleMath : public ModuleBase {
-        enum class MathOperation : char {
-            ADD = 1,
-            SUBTRACT = 2,
-            MULTIPLY = 3,
-            DIVIDE = 4,
-            POWER = 5,
-            LOGARITHM = 6,
-            MINIMUM = 7,
-            MAXIMUM = 8,
-            LESS_THAN = 9,
-            GREATER_THAN = 10
-        };
+    private:
         const std::map<std::string, std::function<double(double, double)>> _ops = {
         const std::map<std::string, std::function<double(double, double)>> _ops = {
             {"add", [](double a, double b) {return a + b; }},
             {"add", [](double a, double b) {return a + b; }},
-            {"subtract", [](double a, double b) {return a - b; }}
+            {"subtract", [](double a, double b) {return a - b; }},
+            {"multiply", [](double a, double b) {return a * b; }},
+            {"divide", [](double a, double b) {return a / b; }},
+            {"power", [](double a, double b) {return pow(a, b); }},
+            {"logarithm", [](double a, double b) {return log(b) / log(a); }},
+            {"minimum", [](double a, double b) {return std::min(a, b); }},
+            {"maximum", [](double a, double b) {return std::max(a, b); }},
+            {"lesser", [](double a, double b) {return a > b; }},
+            {"greater", [](double a, double b) {return a < b; }}
         };
         };
-        std::function<double(double, double)> operation;
-    private:
-        MathOperation _operation;
+        std::function<double(double, double)> _operation;
 
 
-        static std::vector<double> add(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> subtract(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> multiply(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> divide(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> power(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> logarithm(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> minimum(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> maximum(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> less(const std::vector<double>& val1, const std::vector<double>& val2);
-        static std::vector<double> greater(const std::vector<double>& val1, const std::vector<double>& val2);
+        std::vector<double> applyOperation(const std::vector<double>& val1, const std::vector<double>& val2);
 
 
     public:
     public:
-        explicit ModuleMath();
-        bool configure(const std::string& config);
+        ModuleMath();
+        bool configure(const std::string& config) override;
         state update() override;
         state update() override;
-        void setMathOperation(MathOperation operation);
-        MathOperation getMathOperation();
     };
     };
 
 
     ModuleMath::ModuleMath()
     ModuleMath::ModuleMath()
-        : ModuleBase(R"JSON({"operation":"add"})JSON"){
+        : ModuleBase(R"JSON(
+        [{
+            "name":"operation",
+            "value":"add"
+            "options":  [
+                            "add",
+                            "subtract",
+                            "multiply",
+                            "divide",
+                            "power",
+                            "logarithm",
+                            "minimum",
+                            "maximum",
+                            "lesser", 
+                            "greater"
+                        ]
+        }])JSON")
+    {
+        _ops.at("add");
+        _operation = _ops.find("add")->second;
         std::vector<double> default_val = {1};
         std::vector<double> default_val = {1};
-        addInput("Value", default_val);
-        addInput("Value", default_val);
-        addOutput("Value", default_val);
+        inputs.emplace_back(this, "Value", 0, default_val);
+        inputs.emplace_back(this, "Value", 1, default_val);
+        outputs.emplace_back(this, "Value", 0, default_val);
         setType("Math");
         setType("Math");
     }
     }
 
 
     bool ModuleMath::configure(const std::string& config)
     bool ModuleMath::configure(const std::string& config)
     {
     {
-        _operation = ModuleMath::MathOperation::ADD;
         json config_parsed = json::parse(config);
         json config_parsed = json::parse(config);
-        if(config_parsed.contains("operation"))
+        for (size_t i = 0; i < config_parsed.size(); i++)
         {
         {
-            const std::string op = config_parsed["operation"];
-            if("multiply" == op)
+            if (config_parsed[i].contains("name"))
             {
             {
-                _operation = ModuleMath::MathOperation::MULTIPLY;
-            }
-            else if ("add" == op)
-            {
-                _operation = ModuleMath::MathOperation::ADD;
-            }
-        }
-    }
-
-    std::vector<double> ModuleMath::add(const std::vector<double>&val1, const std::vector<double>&val2) {
-        std::vector<double> ret; //= json::array();
-        size_t length= std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] + val2[i]);
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(val1[0] + val2[i]);
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(val1[i] + val2[0]);
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::subtract(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] - val2[i]);
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(val1[0] - val2[i]);
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(val1[i] - val2[0]);
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::multiply(const std::vector<double>&val1, const std::vector<double> &val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] * val2[i]);
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(val1[0] * val2[i]);
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(val1[i] * val2[0]);
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::divide(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] / val2[i]);
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(val1[0] / val2[i]);
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(val1[i] / val2[0]);
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::power(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(pow(val1[i] , val2[i]));
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(pow(val1[0] , val2[i]));
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(pow(val1[i] , val2[0]));
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::logarithm(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                
-                ret.push_back(log(val2[i]) / log(val1[i]));
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(log(val2[i]) / log(val1[0]));
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(log(val2[0]) / log(val1[i]));
-            }
-        }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::minimum(const std::vector<double>&val1, const std::vector<double>&val2){
-            std::vector<double> ret; //= json::array();
-            size_t length = std::max(val1.size(), val2.size());
-            for (int i = 0; i < length; i++) {
-                if (val1.size() == val2.size()) {
-                    ret.push_back(std::min(val1[i], val2[i]));
-                }
-                else if (1 == val1.size()) {
-                    ret.push_back(std::min(val1[0], val2[i]));
+                if (config_parsed[i]["name"].get<std::string>() == "operation")
+                {
+                    const std::string op = config_parsed[i]["value"].get<std::string>();
+                    auto it = _ops.find(op);
+                    if (it != _ops.end())
+                    {
+                        _operation = it->second;
+                        return true;
+                    }
                 }
                 }
-                else if (1 == val2.size()) {
-                    ret.push_back(std::min(val1[i], val2[0]));
-                }
-            }
-            return ret;
-    }
-
-    std::vector<double> ModuleMath::maximum(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(std::max(val1[i], val2[i]));
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(std::max(val1[0], val2[i]));
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(std::max(val1[i], val2[0]));
             }
             }
         }
         }
-        return ret;
-    }
-
-    std::vector<double> ModuleMath::less(const std::vector<double>&val1, const std::vector<double>&val2){
-        std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
-        for (int i = 0; i < length; i++) {
-            if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] > val2[i]);
-            }
-            else if (1 == val1.size()) {
-                ret.push_back(val1[0] > val2[i]);
-            }
-            else if (1 == val2.size()) {
-                ret.push_back(val1[i] > val2[0]);
-            }
-        }
-        return ret;
+        
+        return false;
     }
     }
 
 
-    std::vector<double> ModuleMath::greater(const std::vector<double>&val1, const std::vector<double>&val2){
+    std::vector<double> ModuleMath::applyOperation(const std::vector<double>&val1, const std::vector<double>&val2) {
         std::vector<double> ret; //= json::array();
         std::vector<double> ret; //= json::array();
-        size_t length = std::max(val1.size(), val2.size());
+        size_t length= std::max(val1.size(), val2.size());
         for (int i = 0; i < length; i++) {
         for (int i = 0; i < length; i++) {
             if (val1.size() == val2.size()) {
             if (val1.size() == val2.size()) {
-                ret.push_back(val1[i] < val2[i]);
+                ret.push_back(_operation(val1[i], val2[i]));
             }
             }
             else if (1 == val1.size()) {
             else if (1 == val1.size()) {
-                ret.push_back(val1[0] < val2[i]);
+                ret.push_back(_operation(val1[0], val2[i]));
             }
             }
             else if (1 == val2.size()) {
             else if (1 == val2.size()) {
-                ret.push_back(val1[i] < val2[0]);
+                ret.push_back(_operation(val1[i], val2[0]));
             }
             }
         }
         }
         return ret;
         return ret;
     }
     }
 
 
     state ModuleMath::update() {
     state ModuleMath::update() {
-        std::vector<double> ret = getOutput(0)->getValue();
-
-        switch (_operation) {
-        case MathOperation::ADD:
-                ret = add(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::SUBTRACT:
-                ret = subtract(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::MULTIPLY:
-                ret = multiply(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::DIVIDE:
-                ret = divide(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::POWER:
-                ret = power(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::LOGARITHM:
-                ret = logarithm(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::MINIMUM:
-                ret = minimum(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::MAXIMUM:
-                ret = maximum(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::LESS_THAN:
-                ret = less(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-
-            case MathOperation::GREATER_THAN:
-                ret = greater(getInput(0)->getValue(), getInput(1)->getValue());
-                break;
-        }
-        
+        std::vector<double> ret = applyOperation(getInput(0)->getValue(), getInput(1)->getValue());
         return getOutput(0)->setValue(ret);
         return getOutput(0)->setValue(ret);
     }
     }
 
 
-
-    void ModuleMath::setMathOperation(MathOperation operation){
-        _operation = operation;
-    }
-
-    ModuleMath::MathOperation ModuleMath::getMathOperation(){
-        return _operation;
-    }
-
 }
 }
-ADD_GENERATOR(mdd::ModuleMath);
 
 
 //gdb
 //gdb
 //catch throw
 //catch throw

+ 54 - 12
lib/src/ModuleMerge.cpp

@@ -1,26 +1,44 @@
-#include "ModuleMerge.h"
-#include <boost/algorithm/string.hpp>
+#include "ModuleBase.h"
+//#include <boost/algorithm/string.hpp>
 
 
 namespace mdd {
 namespace mdd {
-	ModuleMerge::ModuleMerge() {
+	class ModuleMerge : public ModuleBase {
+	private:
+
+	public:
+		ModuleMerge();
+		int addModuleInput();
+		int removeModuleInput();
+		std::string setInputType(const std::string& input_id, const std::string& new_type);
+		bool configure(const std::string& config) override;
+		state update() override;
+	};
+	ModuleMerge::ModuleMerge()
+		:ModuleBase(R"JSON(
+        [{
+            "name":"inputs",
+            "value":[{"type": "Value", "value": [1]}, {"type": "Value": [1]}]
+        }])JSON")
+	{
+		configure(getBaseConfiguration());
 		std::vector<double> default_val = { 1 };
 		std::vector<double> default_val = { 1 };
-		addInput("Value", default_val);
-		addInput("Value", default_val);
-		addOutput("Value", default_val);
+		outputs.emplace_back(this, "Value", 0, default_val);
 		setType("Merge");
 		setType("Merge");
 	}
 	}
 
 
 	int ModuleMerge::addModuleInput() {
 	int ModuleMerge::addModuleInput() {
 		std::vector<double> default_val = { 1 };
 		std::vector<double> default_val = { 1 };
-		return addInput("Value", default_val);
+		inputs.emplace_back(this, "Value", inputs.size(), default_val);
+		return inputs.size();
 	}
 	}
 
 
 	int ModuleMerge::removeModuleInput() {
 	int ModuleMerge::removeModuleInput() {
-		return pop_backInput();
+		inputs.pop_back();
+		return inputs.size();
 	}
 	}
 
 
 	std::string ModuleMerge::setInputType(const std::string& input_id, const std::string& new_type) {
 	std::string ModuleMerge::setInputType(const std::string& input_id, const std::string& new_type) {
-		for (int id = 0; id < getInputs().size(); ++id) {
+		for (int id = 0; id < inputs.size(); ++id) {
 			if (getInput(id)->getID() == input_id) {
 			if (getInput(id)->getID() == input_id) {
 				getInput(id)->setType(new_type);
 				getInput(id)->setType(new_type);
 				return getInput(id)->getID();
 				return getInput(id)->getID();
@@ -28,12 +46,36 @@ namespace mdd {
 		}
 		}
 		return "";
 		return "";
 	}
 	}
+
+	bool ModuleMerge::configure(const std::string& config) {
+		json config_parsed = json::parse(config);
+		for (size_t i = 0; i < config_parsed.size(); i++)
+		{
+			if (config_parsed[i].contains("name"))
+			{
+				if (config_parsed[i]["name"].get<std::string>() == "inputs")
+				{
+					size_t length = inputs.size();
+					for (size_t j = length; j < config_parsed[i]["value"].size(); j++)
+					{
+						inputs.emplace_back(this, config_parsed[i]["value"][j]["type"].get<std::string>(), j, config_parsed[i]["value"][j]["value"].get<std::vector<double>>());
+					}
+					for (size_t j = 0; j < length; j++)
+					{
+						inputs[j]->setType(config_parsed[i]["value"][j]["type"].get<std::string>());
+						inputs[j]->setValue(config_parsed[i]["value"][j]["value"].get<std::vector<double>>());
+					}
+				}
+			}
+		}
+
+		return false;
+	}
+
 	state ModuleMerge::update() {
 	state ModuleMerge::update() {
 		std::vector<double>  ret;
 		std::vector<double>  ret;
-		for (size_t i = 0; i < getInputs().size(); i++)
+		for (size_t i = 0; i < inputs.size(); i++)
 		{
 		{
-			std::string key = getInput(i)->getType();
-			boost::algorithm::to_lower(key);
 			for (size_t j = 0; j < getInput(i)->getValue().size(); j++)
 			for (size_t j = 0; j < getInput(i)->getValue().size(); j++)
 			{
 			{
 				ret.push_back(getInput(i)->getValue()[j]);
 				ret.push_back(getInput(i)->getValue()[j]);

+ 49 - 4
lib/src/ModuleParameter.cpp

@@ -1,14 +1,59 @@
-#include "ModuleParameter.h"
+#include "ModuleBase.h"
 
 
 namespace mdd {
 namespace mdd {
-    ModuleParameter::ModuleParameter() {
+    class ModuleParameter : public ModuleBase {
+    private:
+
+    public:
+        ModuleParameter();
+        state update() override;
+        std::string setType(const std::string& type) override;
+        std::string setAppendix(int appendix) override;
+        bool configure(const std::string& config);
+    };
+    ModuleParameter::ModuleParameter()
+        : ModuleBase(R"JSON(
+        [{
+            "name":"appendix",
+            "value":0
+        }])JSON")
+    {
         std::vector<double> default_val = { 1 };
         std::vector<double> default_val = { 1 };
-        addInput("Value", default_val);
-        addOutput("Value", default_val);
+        inputs.emplace_back("Value", 0, default_val);
+        outputs.emplace_back("Value", 0, default_val);
         setType("Parameter");
         setType("Parameter");
     }
     }
 
 
     state ModuleParameter::update() {
     state ModuleParameter::update() {
         return getOutput(0)->setValue(getInput(0)->getValue());
         return getOutput(0)->setValue(getInput(0)->getValue());
     }
     }
+
+    std::string ModuleParameter::setType(const std::string& type) {
+        inputs[0]->setType(type);
+        outputs[0]->setType(type);
+        return ModuleBase::setType(type);
+    }
+
+    std::string ModuleParameter::setAppendix(int appendix)
+    {
+        inputs[0]->setAppendix(appendix);
+        outputs[0]->setAppendix(appendix);
+        return ModuleBase::setAppendix(appendix);
+    }
+    bool ModuleParameter::configure(const std::string& config)
+    {
+        json config_parsed = json::parse(config);
+        for (size_t i = 0; i < config_parsed.size(); i++)
+        {
+            if (config_parsed[i].contains("name"))
+            {
+                if (config_parsed[i]["name"].get<std::string>() == "appendix")
+                {
+                    setAppendix(config_parsed[i]["value"].get<int>());
+                }
+            }
+        }
+
+        return false;
+    }
 }
 }

+ 97 - 51
lib/src/ModuleSQL.cpp

@@ -1,7 +1,28 @@
-#include "ModuleSQL.h"
+#include "ModuleBase.h"
+#include <iostream>
+#include <string>
+#include <sqlite3.h>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string.hpp>
 
 
 namespace mdd {
 namespace mdd {
+	class ModuleSQL : public ModuleBase {
+	private:
+		sqlite3* _db;
+		std::string _tbname;
+		void erase_keyword(std::string& str, std::string key);
+		struct _entity {
+			std::string key;
+			std::string type;
+		};
+		std::vector<_entity> _content;
+
+	public:
+		ModuleSQL();
+		~ModuleSQL();
+		bool configure(const std::string& config) override;
+		state update() override;
+	};
+
 	void ModuleSQL::erase_keyword(std::string& str, std::string key) {
 	void ModuleSQL::erase_keyword(std::string& str, std::string key) {
 		while (true) {
 		while (true) {
 			int start = (int)str.find(key);
 			int start = (int)str.find(key);
@@ -14,11 +35,78 @@ namespace mdd {
 		}
 		}
 	}
 	}
 
 
-	ModuleSQL::ModuleSQL(std::string dbname) {
+	ModuleSQL::ModuleSQL()
+	: ModuleBase(R"JSON(
+        [{
+            "name":"database",
+            "value":""
+        }])JSON")
+	{
+		configure(getBaseConfiguration());
+		setType("SQL");
+	}
+
+	state ModuleSQL::update() {
+		int rc;
+		std::string sql;
+		sqlite3_stmt* res;
+		int step;
+		// Create SQL statement
+		sql = "SELECT * "\
+			"FROM " + _tbname + " "\
+			"WHERE " + _content[0].key + " = " + std::to_string(getInput(0)->getValue()[0]);
+
+		std::cout << sql << std::endl;
+
+		// Execute SQL statement
+		rc = sqlite3_prepare_v2(_db, sql.c_str(), -1, &res, 0);
+
+		if (rc != SQLITE_OK) {
+			fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(_db));
+			sqlite3_close(_db);
+		}
+		else {
+			fprintf(stdout, "Operation done successfully\n");
+		}
+
+		step = sqlite3_step(res);
+		state state = state::UNCHANGED;
+		if (step == SQLITE_ROW) {
+			int nCol = sqlite3_column_count(res);
+			std::string parse_str = "{\"" + _tbname + "\" : {";
+			for (size_t i = 0; i < nCol; i++)
+			{
+				//json val = (char*)sqlite3_column_text(res, i);
+				getOutput(i)->setValue({ std::atof((char*)sqlite3_column_text(res, i)) });
+			}
+		}
+		sqlite3_finalize(res);
+
+		return state;
+	}
+
+	ModuleSQL::~ModuleSQL() {
+		sqlite3_close(_db);
+	}
+
+	bool ModuleSQL::configure(const std::string& config) {
+		json config_parsed = json::parse(config);
+		std::string dbname;
+		for (size_t i = 0; i < config_parsed.size(); i++)
+		{
+			if (config_parsed[i].contains("name"))
+			{
+				if (config_parsed[i]["name"].get<std::string>() == "database")
+				{
+					dbname = config_parsed[i]["value"].get<std::string>();
+				}
+			}
+		}
+		
 		int rc = sqlite3_open(dbname.c_str(), &_db);
 		int rc = sqlite3_open(dbname.c_str(), &_db);
 		if (rc) {
 		if (rc) {
 			fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(_db));
 			fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(_db));
-			return;
+			return false;
 		}
 		}
 		else {
 		else {
 			fprintf(stderr, "Opened database successfully\n");
 			fprintf(stderr, "Opened database successfully\n");
@@ -90,7 +178,7 @@ namespace mdd {
 			sql_res.erase(new_end, sql_res.end());
 			sql_res.erase(new_end, sql_res.end());
 
 
 			_content.clear();
 			_content.clear();
-			while(true){
+			while (true) {
 				end = sql_res.find(" ,");
 				end = sql_res.find(" ,");
 				if (end == -1)
 				if (end == -1)
 				{
 				{
@@ -115,54 +203,12 @@ namespace mdd {
 		}
 		}
 		sqlite3_finalize(res);
 		sqlite3_finalize(res);
 
 
-		addInput(_content[0].key, {0});
-		for (auto& cont :_content)
+		inputs.emplace_back(this, _content[0].key, inputs.size(), std::vector<double>{0});
+		for (auto& cont : _content)
 		{
 		{
-			addOutput(cont.key, {1});
-		}
-		setType("SQL");
-	}
-
-	state ModuleSQL::update() {
-		int rc;
-		std::string sql;
-		sqlite3_stmt* res;
-		int step;
-		// Create SQL statement
-		sql = "SELECT * "\
-			"FROM " + _tbname + " "\
-			"WHERE " + _content[0].key + " = " + std::to_string(getInput(0)->getValue()[0]);
-
-		std::cout << sql << std::endl;
-
-		// Execute SQL statement
-		rc = sqlite3_prepare_v2(_db, sql.c_str(), -1, &res, 0);
-
-		if (rc != SQLITE_OK) {
-			fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(_db));
-			sqlite3_close(_db);
-		}
-		else {
-			fprintf(stdout, "Operation done successfully\n");
-		}
-
-		step = sqlite3_step(res);
-		state state = state::UNCHANGED;
-		if (step == SQLITE_ROW) {
-			int nCol = sqlite3_column_count(res);
-			std::string parse_str = "{\"" + _tbname + "\" : {";
-			for (size_t i = 0; i < nCol; i++)
-			{
-				//json val = (char*)sqlite3_column_text(res, i);
-				getOutput(i)->setValue({ std::atof((char*)sqlite3_column_text(res, i)) });
-			}
+			outputs.emplace_back(this, cont.key, outputs.size(), std::vector<double>{1});
 		}
 		}
-		sqlite3_finalize(res);
-
-		return state;
-	}
-
-	ModuleSQL::~ModuleSQL() {
-		sqlite3_close(_db);
+		
+		return true;
 	}
 	}
 }
 }

+ 57 - 7
lib/src/ModuleSwitch.cpp

@@ -1,15 +1,65 @@
-#include "ModuleSwitch.h"
+#include "ModuleBase.h"
 #include <iostream>
 #include <iostream>
 
 
 namespace mdd{
 namespace mdd{
-    ModuleSwitch::ModuleSwitch(){
-        std::vector<double> default_val = { 42 };
-        addInput("Switch", default_val);
-        addInput("Value", default_val);
-        addInput("Default", default_val);
-        addOutput("Value", default_val);
+    class ModuleSwitch : public ModuleBase {
+    public:
+        ModuleSwitch();
+        bool configure(const std::string& config) override;
+        state update() override;
+    };
+    ModuleSwitch::ModuleSwitch()
+        :ModuleBase(R"JSON(
+        [{
+            "name":"size",
+            "value": 1
+        }])JSON")
+    {    
+        std::vector<double> default_val = { 1 };
+        inputs.emplace_back(this, "Switch", 0, default_val);
+        inputs.emplace_back(this, "Default", 0, default_val);
+        configure(getBaseConfiguration());
+        outputs.emplace_back(this, "Value", 0, default_val);
         setType("Switch");
         setType("Switch");
     }
     }
+    bool ModuleSwitch::configure(const std::string& config) {
+        json config_parsed = json::parse(config);
+        for (size_t i = 0; i < config_parsed.size(); i++)
+        {
+            if (config_parsed[i].contains("name"))
+            {
+                if (config_parsed[i]["name"].get<std::string>() == "size")
+                {
+                    size_t length = config_parsed[i]["value"].get<size_t>();
+                    if (length != inputs.size() -1)
+                    {
+                        size_t length_before = inputs.size();
+                        if (length_before != 1)
+                        {
+                            inputs.back()->setType("Value");
+                        }
+                        
+                        for (size_t j = length_before - 1; j < length; j++)
+                        {
+                            inputs.emplace_back(this, "Value", inputs.size() - 1, std::vector<double>{1});
+                        }
+                        for (size_t j = length; j < length_before-1; j++)
+                        {
+                            inputs.pop_back();
+                        }
+                        if (length != 0)
+                        {
+                            inputs.back()->setType("Default");
+                        }
+                    }
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
     state ModuleSwitch::update(){
     state ModuleSwitch::update(){
         std::vector<double> ret;
         std::vector<double> ret;
         size_t length = getInput(0)->getValue().size();
         size_t length = getInput(0)->getValue().size();

+ 23 - 9
lib/src/Output.cpp

@@ -15,11 +15,11 @@ namespace mdd {
         }
         }
         return _connections.size();
         return _connections.size();
     }
     }
-    Output::Output( const std::string& type, int appendix, const std::vector<double>& initial) :
-            _state(state::UNCHANGED)
+    Output::Output(IModule* parent, const std::string& type, int appendix, const std::vector<double>& initial) :
+            _state(state::UNCHANGED),
+            _parent(parent)
     {
     {
         _appendix = appendix;
         _appendix = appendix;
-        _prefix = "";
         _type = type;
         _type = type;
         _value = initial;
         _value = initial;
         _optimizable = false;
         _optimizable = false;
@@ -61,18 +61,22 @@ namespace mdd {
     }
     }
 
 
     std::string Output::getID(){
     std::string Output::getID(){
-        return _prefix + "/" + _type + std::to_string(_appendix);
-    }
-
-    std::string Output::setPrefix(const std::string& prefix){
-        _prefix = prefix;
-        return getID();
+        return _type + std::to_string(_appendix);
     }
     }
 
 
     std::string Output::setAppendix(int appendix){
     std::string Output::setAppendix(int appendix){
         _appendix = appendix;
         _appendix = appendix;
         return getID();
         return getID();
     }
     }
+
+    int Output::getAppendix() {
+        return _appendix;
+    }
+
+    std::string Output::getParentID() {
+        return _parent->getID();
+    }
+
     bool Output::connect(std::shared_ptr<IInput> input)
     bool Output::connect(std::shared_ptr<IInput> input)
     {
     {
         addConnection(input);
         addConnection(input);
@@ -83,4 +87,14 @@ namespace mdd {
     {
     {
         return _connections;
         return _connections;
     }
     }
+    void Output::disconnect() {
+        for (size_t i = 0; i < _connections.size(); i++)
+        {
+            if (_connections[i] != nullptr)
+            {
+                _connections[i]->removeConnection(std::make_shared<Output>((*this)));
+            }
+        }
+        _connections.clear();
+    }
 }
 }

+ 193 - 210
lib/src/ProcessorBase.cpp

@@ -1,313 +1,296 @@
 #include "ProcessorBase.h"
 #include "ProcessorBase.h"
 
 
-
-
 namespace mdd{
 namespace mdd{
+    ProcessorBase::ProcessorBase(const std::string& base_config)
+    : _base_config(base_config)
+    {
 
 
-    int ProcessorBase::addProcesorInput(const std::string &type, const std::vector<double>&value){
-        _processor_inputs.push_back(std::make_shared<Input>( type, _processor_inputs.size(), value));
-        _processor_inputs[_processor_inputs.size() - 1]->setPrefix(getID());
-        return  _processor_inputs.size()-1;
-    }
-
-    int ProcessorBase::addProcessorOutput(const std::string& type, const std::vector<double>& initial){
-        _processor_outputs.push_back(std::make_shared<Output>( type, _processor_outputs.size(), initial));
-        _processor_outputs[_processor_outputs.size() - 1]->setPrefix(getID());
-        return  _processor_outputs.size()-1;
-    }
-
-    std::shared_ptr<IOutput> ProcessorBase::getProcessorOutput(int handle){
-
-        return _processor_outputs[handle];
     }
     }
-
-    std::shared_ptr<IInput> ProcessorBase::getProcessorInput(int handle){
-
-        return _processor_inputs[handle];
+    std::shared_ptr<IModule> ProcessorBase::getModule(size_t index){
+        return modules[index];
     }
     }
 
 
-    std::shared_ptr<IModule> ProcessorBase::getModule(int handle){
-        return _modules[handle];
-    }
-
-    void ProcessorBase::updateID(){
-        std::string new_prefix =  getID();
-        for (auto &input  : _processor_inputs){
-            input->setPrefix(new_prefix);
-        }
-        for (auto &output  : _processor_outputs){
-            output->setPrefix(new_prefix);
-        }
-        for (auto& module : _modules) {
-            module->setPrefix(new_prefix);
-        }
+    std::string ProcessorBase::getBaseConfiguration() {
+        return _base_config;
     }
     }
 
 
     std::string ProcessorBase::getID() {
     std::string ProcessorBase::getID() {
-        return _prefix + "/" + _type + std::to_string(_appendix);
+        return _type + std::to_string(_appendix);
     }
     }
 
 
     std::string ProcessorBase::setType(const std::string& type){
     std::string ProcessorBase::setType(const std::string& type){
         _type=type;
         _type=type;
-        updateID();
         return getID();
         return getID();
     }
     }
     std::string ProcessorBase::getType(){
     std::string ProcessorBase::getType(){
         return _type;
         return _type;
     }
     }
 
 
-    std::string ProcessorBase::setPrefix(const std::string& prefix){
-        _prefix = prefix;
-        updateID();
-        return getID();
-    }
-
     std::string ProcessorBase::setAppendix(int appendix){
     std::string ProcessorBase::setAppendix(int appendix){
         _appendix = appendix;
         _appendix = appendix;
-        updateID();
         return getID();
         return getID();
     }
     }
 
 
+    int ProcessorBase::getAppendix() {
+        return _appendix;
+    }
+
 
 
     std::string ProcessorBase::addModule(std::shared_ptr<IModule> module){
     std::string ProcessorBase::addModule(std::shared_ptr<IModule> module){
-        _modules.emplace_back(module);
-        _modules.back()->setPrefix(getID());
-        _modules.back()->setAppendix(_modules.size()-1);
-        return _modules.back()->getID();
+        modules.emplace_back(module);
+        modules.back()->setAppendix(modules.size()-1);
+        return modules.back()->getID();
     }
     }
 
 
     void ProcessorBase::removeModule(std::shared_ptr<IModule> module)
     void ProcessorBase::removeModule(std::shared_ptr<IModule> module)
     {
     {
-        for (auto it = _module_inputs.begin(); it != _module_inputs.end(); ++it) {
-            if (it->moduleHandler == module)
-            {
-                _module_inputs.erase(it);
-            }
-        }
-
-        for (auto it = _module_outputs.begin(); it != _module_outputs.end(); ++it) {
-            if (it->moduleHandler == module)
-            {
-                _module_outputs.erase(it);
-            }
-        }
 
 
-        for (auto it = _modules.begin(); it != _modules.end(); ++it) {
+        for (auto it = modules.begin(); it != modules.end(); ++it) {
             if ((*it) == module)
             if ((*it) == module)
             {
             {
-                _modules.erase(it);
+                modules.erase(it);
             }
             }
         }
         }
     }
     }
 
 
-    std::string ProcessorBase::addModuleInput(std::string module_ID, std::string input_ID){
-        int ret = _processor_inputs.size();
-        for (auto& module : _modules) {
-            if(module->getID() == module_ID){
-                _module_inputs.emplace_back(HandlerModule<IInput>(module, module->getInput(input_ID)));
-            }
-        }
-        return _module_inputs.back().accessHandler->getID();
+    std::vector<std::shared_ptr<ModuleParameter>>& ProcessorBase::getInputParams() {
+        return inputs;
     }
     }
 
 
-    std::string ProcessorBase::addModuleInput(std::shared_ptr<IModule> module, std::shared_ptr<IInput> input){
-        _module_inputs.emplace_back(HandlerModule<IInput>(module, input));
-        return _module_inputs.back().accessHandler->getID();
+    std::vector<std::shared_ptr<ModuleParameter>>& ProcessorBase::getOutputParams() {
+        return outputs;
     }
     }
 
 
-    std::string ProcessorBase::addModuleOutput(std::string module_ID, std::string output_ID){
-        for (auto& module : _modules) {
-            if(module->getID() == module_ID){
-                _module_outputs.emplace_back(HandlerModule<IOutput>(module, module->getOutput(output_ID)));
-            }
-        }
-        return _module_outputs.back().accessHandler->getID();
+    size_t ProcessorBase::getNumInputs() {
+        return processor_inputs.size() + inputs.size();
     }
     }
 
 
-    std::string ProcessorBase::addModuleOutput(std::shared_ptr<IModule> module, std::shared_ptr<IOutput> output){
-        _module_outputs.emplace_back(HandlerModule<IOutput>(module, output));
-        return _module_outputs.back().accessHandler->getID();
+    size_t ProcessorBase::getNumOutputs() {
+        return processor_outputs.size() + outputs.size();
     }
     }
-
-    std::vector<std::string> ProcessorBase::getInputs(){
-        std::vector<std::string> ret;
-        for (auto &input  : _processor_inputs) {
-            ret.push_back(input->getType());
-        }
-        for (auto &input  : _module_inputs) {
-            ret.push_back(input.accessHandler->getType());
-        }
-        return ret;
+    std::vector< std::shared_ptr<IModule >>& ProcessorBase::getModules(){
+        return modules;
     }
     }
 
 
-    std::vector<std::string> ProcessorBase::getOutputs(){
-        std::vector<std::string> ret;
-        for (auto &output  : _processor_outputs) {
-            ret.push_back(output->getType());
-        }
-        for (auto &output  : _module_outputs) {
-            ret.push_back(output.accessHandler->getType());
-        }
-        return ret;
+    size_t ProcessorBase::getNumModuls() {
+        return modules.size();
     }
     }
 
 
-    std::vector<std::string> ProcessorBase::getModules(){
-        std::vector<std::string> ret;
-        for (auto &module  : _modules) {
-            ret.push_back(module->getType());
+    std::shared_ptr<IModule> ProcessorBase::getModule(size_t index) {
+        if (index < modules.size())
+        {
+            return modules[index];
         }
         }
-        return ret;
+        return nullptr;
     }
     }
 
 
-    std::vector<std::string> ProcessorBase::getInputIDs(){
-        std::vector<std::string> ret;
-        for (auto &input  : _processor_inputs) {
-            ret.push_back(input->getID());
-        }
-        for (auto &input  : _module_inputs) {
-            ret.push_back(input.accessHandler->getID());
+    bool ProcessorBase::connect(const std::string& output_id, const std::vector<std::string>& input_ids)
+    {
+        std::size_t found = output_id.find_first_of("/");
+        std::string str_module_id = output_id.substr(0, found);
+        std::string str_output_id = output_id.substr( found + 1);
+        std::shared_ptr<IOutput> out_ptr;
+        if (str_module_id.empty())
+        {
+            out_ptr = getOutput(str_output_id);
+        }
+        else {
+            for (size_t i = 0; i < modules.size(); i++)
+            {
+                if (modules[i]->getID() == str_module_id)
+                {
+                    out_ptr = modules[i]->getOutput(str_output_id);
+                    break;
+                }
+            }
         }
         }
-        return ret;
-    }
 
 
-    std::vector<std::string> ProcessorBase::getOutputIDs(){
-        std::vector<std::string> ret;
-        for (auto &output  : _processor_outputs) {
-            ret.push_back(output->getID());
-        }
-        for (auto &output  : _module_outputs) {
-            ret.push_back(output.accessHandler->getID());
-        }
-        return ret;
-    }
+        for (size_t i = 0; i < input_ids.size(); i++)
+        {
+            found = input_ids[i].find_first_of("/");
+            str_module_id = input_ids[i].substr(0, found);
+            std::string str_input_id = input_ids[i].substr(found + 1);
 
 
-    std::vector<std::string> ProcessorBase::getModuleIDs(){
-        std::vector<std::string> ret;
-        for (auto &module  : _modules) {
-            ret.push_back(module->getID());
+            if (str_module_id.empty())
+            {
+                auto in_ptr = getInput(str_input_id);
+                in_ptr->connect(out_ptr);
+            }
+            else {
+                for (size_t i = 0; i < modules.size(); i++)
+                {
+                    if (modules[i]->getID() == str_module_id)
+                    {
+                        auto in_ptr = modules[i]->getInput(str_input_id);
+                        in_ptr->connect(out_ptr);
+                        break;
+                    }
+                }
+            }
         }
         }
-        return ret;
+        return true;
     }
     }
 
 
-    std::vector<state> ProcessorBase::getInputStates() {
-        std::vector<state> ret;
-        for (auto& input : _processor_inputs) {
-            ret.push_back(input->getState());
+    void ProcessorBase::disconnect() {
+        for (size_t i = 0; i < processor_inputs.size(); i++)
+        {
+            processor_inputs[i]->disconnect();
         }
         }
-        for (auto& input : _module_inputs) {
-            ret.push_back(input.accessHandler->getState());
+        for (size_t i = 0; i < processor_outputs.size(); i++)
+        {
+            processor_outputs[i]->disconnect();
         }
         }
-        return ret;
-    }
-    
-    std::vector<state> ProcessorBase::getOutputStates() {
-        std::vector<state> ret;
-        for (auto& output : _processor_outputs) {
-            ret.push_back(output->getState());
+        for (size_t i = 0; i < inputs.size(); i++)
+        {
+            inputs[i]->disconnect();
         }
         }
-        for (auto& output : _module_outputs) {
-            ret.push_back(output.accessHandler->getState());
+        for (size_t i = 0; i < outputs.size(); i++)
+        {
+            outputs[i]->disconnect();
         }
         }
-        return ret;
     }
     }
 
 
-    std::vector<std::shared_ptr<IOutput>> ProcessorBase::getInputConnections()
-    {
-        std::vector<std::shared_ptr<IOutput>> ret;
-        for (auto& input : _processor_inputs) {
-            ret.push_back(input->getConnection());
+    void ProcessorBase::load(const json& j) {
+        for (size_t i = 0; i < j["inputs"].size(); i++)
+        {
+            inputs.emplace_back();
+            inputs.back()->setType(j["inputs"][i]["type"].get<std::string>());
+            inputs.back()->setAppendix(j["inputs"][i]["appendix"].get<int>());
         }
         }
-        for (auto& input : _module_inputs) {
-            ret.push_back(input.accessHandler->getConnection());
+        for (size_t i = 0; i < j["outputs"].size(); i++)
+        {
+            outputs.emplace_back();
+            outputs.back()->setType(j["outputs"][i]["type"].get<std::string>());
+            outputs.back()->setAppendix(j["outputs"][i]["appendix"].get<int>());
         }
         }
-        return ret;
-    }
 
 
-    std::vector<std::vector<std::shared_ptr<IInput>>> ProcessorBase::getOutputConnections()
-    {
-        std::vector<std::vector<std::shared_ptr<IInput>>> ret;
-        for (auto& output : _processor_outputs) {
-            ret.push_back(output->getConnections());
+        auto regi = Registration();
+        for (size_t i = 0; i < j["modules"].size(); i++)
+        {
+            addModule(regi.generateModule(j["modules"][i]["id"].get<std::string>()));
+            modules.back()->setType(j["modules"][i]["type"].get<std::string>());
+            modules.back()->setAppendix(j["modules"][i]["appendix"].get<int>());
+            modules.back()->load(j["modules"][i]["load"]);
         }
         }
-        for (auto& output : _module_outputs) {
-            ret.push_back(output.accessHandler->getConnections());
+        for (size_t i = 0; i < j["connections"].size(); i++)
+        {
+            connect(j["connections"][i]["output"].get<std::string>(), j["connections"][i]["inputs"].get<std::vector<std::string>>());
         }
         }
-        return ret;
+       
     }
     }
 
 
-    std::vector <std::shared_ptr<IInput>> ProcessorBase::getOptimizableInputs() 
-    {
-        std::vector<std::shared_ptr<IInput>> ret;
-        for (auto& input : _processor_inputs) {
-            if (input->isOptimizable())
-            {
-                ret.push_back(input);
-            }
+    json ProcessorBase::dump() {
+        //update module apendix ?
+
+        json ret;
+        ret["inputs"];
+        for (size_t i = 0; i < inputs.size(); i++)
+        {
+            json sub;
+            sub["type"] = inputs[i]->getType();
+            sub["appendix"] = inputs[i]->getAppendix();
+            ret["inputs"].push_back(sub);
         }
         }
-        for (auto& mod : _modules) {
-            auto in = mod->getOptimizableInputs();
-            for (size_t i = 0; i < in.size(); i++)
+
+        ret["outputs"];
+        for (size_t i = 0; i < outputs.size(); i++)
+        {
+            json sub;
+            sub["type"] = outputs[i]->getType();
+            sub["appendix"] = outputs[i]->getAppendix();
+            ret["outputs"].push_back(sub);
+        }
+
+        ret["modules"];
+        ret["connections"];
+        for (size_t i = 0; i < modules.size(); i++)
+        {
+            json sub;
+            sub["id"] = typeid((*modules[i])).name();
+            sub["type"] = modules[i]->getType();
+            sub["appendix"] = modules[i]->getAppendix();
+            sub["configure"] = modules[i]->dump();
+            ret["modules"].push_back(sub);
+            for (size_t j = 0; j < modules[i]->getNumOutputs(); j++)
             {
             {
-                ret.push_back(in[i]);
+                auto connections = modules[i]->getOutput(j)->getConnections();
+                if (!connections.empty())
+                {
+                    json connect;
+                    connect["output"] = modules[i]->getOutput(j)->getParentID() + "/" + modules[i]->getOutput(j)->getID();
+                    for (size_t k = 0; k < connections.size(); k++)
+                    {
+                        connect["inputs"].push_back(connections[k]->getParentID() + "/" + connections[k]->getID());
+                    }
+                    ret["connections"].push_back(connect);
+                }
             }
             }
         }
         }
         return ret;
         return ret;
     }
     }
 
 
-    std::vector <std::shared_ptr<IOutput>> ProcessorBase::getOptimizableOutputs()
-    {
-        std::vector<std::shared_ptr<IOutput>> ret;
-        for (auto& output : _processor_outputs) {
-            if (output->isOptimizable())
-            {
-                ret.push_back(output);
-            }
+    std::shared_ptr<IOutput> ProcessorBase::getOutput(size_t index) {
+        if (index < processor_outputs.size())
+        {
+            return processor_outputs[index];
         }
         }
-        for (auto& mod : _modules) {
-            auto out = mod->getOptimizableOutputs();
-            for (size_t i = 0; i < out.size(); i++)
-            {
-                ret.push_back(out[i]);
-            }
+        index -= processor_inputs.size();
+        if (index < outputs.size())
+        {
+            return outputs[index]->getOutput(0);
         }
         }
-        
-        return ret;
+        return nullptr;
     }
     }
-
-    std::shared_ptr<IOutput> ProcessorBase::getOutput(const std::string& output_id){
-        for (auto& output : _processor_outputs) {
-            if(output->getID() == output_id){
+   
+    std::shared_ptr<IOutput> ProcessorBase::getOutput(const std::string& id){
+        for (auto& output : processor_outputs) {
+            if(output->getID() == id){
                 return output;
                 return output;
             }
             }
         }
         }
-        for (auto& output : _module_outputs) {
-            if(output.accessHandler->getID() == output_id){
-                return output.accessHandler;
+        for (auto& output : outputs) {
+            if(output->getOutput(0)->getID() == id){
+                return output->getOutput(0);
             }
             }
         }
         }
         return nullptr;
         return nullptr;
     }
     }
 
 
-    std::shared_ptr<IInput> ProcessorBase::getInput(const std::string& input_id){
-        for (auto& input : _processor_inputs) {
-            if(input->getID() == input_id){
+    std::shared_ptr<IInput> ProcessorBase::getInput(size_t index) {
+        if (index < processor_inputs.size())
+        {
+            return processor_inputs[index];
+        }
+        index -= processor_inputs.size();
+        if (index < inputs.size())
+        {
+            return inputs[index]->getInput(0);
+        }
+        return nullptr;
+    }
+
+    std::shared_ptr<IInput> ProcessorBase::getInput(const std::string& id){
+        for (auto& input : processor_inputs) {
+            if(input->getID() == id){
                 return input;
                 return input;
             }
             }
         }
         }
-        for (auto& input : _module_inputs) {
-            if(input.accessHandler->getID() == input_id){
-                return input.accessHandler;
+        for (auto& input : inputs) {
+            if (input->getInput(0)->getID() == id) {
+                return input->getInput(0);
             }
             }
         }
         }
         return nullptr;
         return nullptr;
     }
     }
 
 
-    std::shared_ptr<IModule> ProcessorBase::getModule(std::string module_id){
-        for (auto& module : _modules) {
-            if(module->getID() == module_id){
+    std::shared_ptr<IModule> ProcessorBase::getModule(const std::string& id){
+        for (auto& module : modules) {
+            if(module->getID() == id){
                 return module;
                 return module;
             }
             }
         }
         }
         return nullptr;
         return nullptr;
     }
     }
+
+
 }
 }

+ 0 - 0
lib/src/ProcessorEvolution.cpp


+ 107 - 23
lib/src/ProcessorStandard.cpp

@@ -1,13 +1,101 @@
-#include "ProcessorStandard.h"
+#include "ProcessorBase.h"
 #include <iostream>
 #include <iostream>
+#include "Output.h"
+#include <chrono>
 
 
 namespace mdd {
 namespace mdd {
-    ProcessorStandard::ProcessorStandard(priority priorityEvaluation , int maxIterations):
-        priorityEvaluation(priorityEvaluation),
-        maxIterations(maxIterations)
+    enum priority {
+        MANUAL,
+        STATIC,
+        DYNAMIC,
+        TIME
+    };
+
+    class ProcessorStandard : public ProcessorBase {
+    private:
+        struct module_priority {
+            std::shared_ptr<IModule> module_ptr;
+            size_t inputCounter;
+            size_t changeCounter;
+            size_t outputCounter;
+            int time_priority;
+            module_priority(std::shared_ptr<IModule> module, size_t inputs = 0, size_t outputs = 0, size_t change = 0);
+        };
+        std::vector<module_priority> _priority_list;
+        int _maxIterations;
+        priority _priorityEvaluation;
+    public:
+        ProcessorStandard();
+        bool configure(const std::string& config) override;
+        std::string addModule(std::shared_ptr<IModule> module) override;
+        void removeModule(std::shared_ptr<IModule> module) override;
+        std::vector<std::shared_ptr<IModule>> getModulePriority();
+        state update() override;
+        std::shared_ptr<IOutput> getIteration();
+    };
+
+    ProcessorStandard::ProcessorStandard()
+        :ProcessorBase(R"JSON(
+        [{
+            "name":"priority",
+            "value":"manual"
+            "options":  [
+                            "manual",
+                            "static",
+                            "dynamic",
+                            "time"                     
+                        ]
+        },{
+            "name":"iterations",
+            "value": -1
+        }
+        ])JSON")
     {
     {
+        _priorityEvaluation = MANUAL;
+        _maxIterations = -1;
         setType("StandardProcessor");
         setType("StandardProcessor");
-        addProcessorOutput("Iterator", {0});
+        processor_outputs.emplace_back(this, "Iterator", 0, std::vector<double>{0});
+    }
+
+    bool ProcessorStandard::configure(const std::string& config) {
+        json config_parsed = json::parse(config);
+        bool found = false;
+        for (size_t i = 0; i < config_parsed.size(); i++)
+        {
+            if (config_parsed[i].contains("name"))
+            {
+                if (config_parsed[i]["name"].get<std::string>() == "priority")
+                {
+                    auto op = config_parsed[i]["value"].get<std::string>();
+                    found = true;
+                    switch (op.c_str())
+                    {
+                    case "manual":
+                        _priorityEvaluation = MANUAL;
+                        break;
+                    case "static":
+                        _priorityEvaluation = STATIC;
+                        break;
+                    case "dynamic":
+                        _priorityEvaluation = DYNAMIC;
+                        break;
+                    case "time":
+                        _priorityEvaluation = TIME;
+                        break;
+                    default:
+                        found = false;
+                        break;
+                    }
+                }
+                if (config_parsed[i]["name"].get<std::string>() == "iterations")
+                {
+                    _maxIterations = config_parsed[i]["value"].get<int>();
+                    found = true;
+                }
+            }
+        }
+
+        return found;
     }
     }
 
 
     std::string ProcessorStandard::addModule(std::shared_ptr<IModule> module)
     std::string ProcessorStandard::addModule(std::shared_ptr<IModule> module)
@@ -39,24 +127,21 @@ namespace mdd {
     }
     }
 
 
     state ProcessorStandard::update() {
     state ProcessorStandard::update() {
-        if (priorityEvaluation != MANUAL)
+        if (_priorityEvaluation != MANUAL)
         {
         {
             //update priorities
             //update priorities
             for (auto it = _priority_list.begin(); it != _priority_list.end(); ++it) {
             for (auto it = _priority_list.begin(); it != _priority_list.end(); ++it) {
                 //collect connected inputs
                 //collect connected inputs
-                auto input_connections = it->module_ptr->getInputConnections();
                 it->inputCounter = 0;
                 it->inputCounter = 0;
-                for (auto it_c = input_connections.begin(); it_c != input_connections.end(); ++it_c) {
-                    if ((*it_c) != nullptr)
+                for (size_t i = 0; i < it->module_ptr->getNumInputs(); ++i) {
+                    if (it->module_ptr->getInput(i)->getConnection() != nullptr)
                     {
                     {
                         ++(it->inputCounter);
                         ++(it->inputCounter);
                     }
                     }
                 }
                 }
                 //collect connected outputs
                 //collect connected outputs
-                auto output_connections = it->module_ptr->getOutputConnections();
-                it->outputCounter = 0;
-                for (auto it_c = output_connections.begin(); it_c != output_connections.end(); ++it_c) {
-                    if (!(*it_c).empty())
+                for (size_t i = 0; i < it->module_ptr->getNumOutputs(); ++i) {
+                    if (!it->module_ptr->getOutput(i)->getConnections().empty())
                     {
                     {
                         ++(it->outputCounter);
                         ++(it->outputCounter);
                     }
                     }
@@ -78,14 +163,14 @@ namespace mdd {
         state group_state = state::CHANGED;
         state group_state = state::CHANGED;
         size_t restart = 0;
         size_t restart = 0;
         while (group_state == state::CHANGED) {
         while (group_state == state::CHANGED) {
-            getProcessorOutput(0)->setValue()[0] += 1;
-            getProcessorOutput(0)->resetState();
+            processor_outputs[0]->setValue()[0] += 1;
+            processor_outputs[0]->resetState();
             group_state = state::UNCHANGED;
             group_state = state::UNCHANGED;
             for (int i = restart; i < _priority_list.size(); ++i) {
             for (int i = restart; i < _priority_list.size(); ++i) {
                 auto t_start = Time::now();
                 auto t_start = Time::now();
                 state module_state = _priority_list[i].module_ptr->update();
                 state module_state = _priority_list[i].module_ptr->update();
                 auto t_end = Time::now();
                 auto t_end = Time::now();
-                if (priorityEvaluation == TIME)
+                if (_priorityEvaluation == TIME)
                 {
                 {
                     _priority_list[i].time_priority = std::round(std::log10(std::chrono::duration_cast<std::chrono::milliseconds>(t_end - t_start).count()));
                     _priority_list[i].time_priority = std::round(std::log10(std::chrono::duration_cast<std::chrono::milliseconds>(t_end - t_start).count()));
                 }
                 }
@@ -94,18 +179,17 @@ namespace mdd {
                     ret = state::CHANGED;
                     ret = state::CHANGED;
                 }
                 }
                 // ignore modules which have to initilize once in the future
                 // ignore modules which have to initilize once in the future
-                if (_priority_list[i].inputCounter == 0 && priorityEvaluation != MANUAL) {
+                if (_priority_list[i].inputCounter == 0 && _priorityEvaluation != MANUAL) {
                     restart = i;
                     restart = i;
                 }
                 }
-                if ((priorityEvaluation == DYNAMIC || priorityEvaluation == TIME) && _priority_list.size() < i+1) {
+                if ((_priorityEvaluation == DYNAMIC || _priorityEvaluation == TIME) && _priority_list.size() < i+1) {
                     if (_priority_list[i + 1].inputCounter == _priority_list[i].inputCounter && _priority_list[i + 1].inputCounter != 0)
                     if (_priority_list[i + 1].inputCounter == _priority_list[i].inputCounter && _priority_list[i + 1].inputCounter != 0)
                     {
                     {
                         //collect changes
                         //collect changes
                         for (auto it = _priority_list.begin() + i + 1; it != _priority_list.end(); ++it) {
                         for (auto it = _priority_list.begin() + i + 1; it != _priority_list.end(); ++it) {
-                            auto input_states = it->module_ptr->getInputStates();
                             it->changeCounter = 0;
                             it->changeCounter = 0;
-                            for (auto it_c = input_states.begin(); it_c != input_states.end(); ++it_c) {
-                                if ((*it_c) == state::CHANGED)
+                            for (size_t i = 0; i < it->module_ptr->getNumInputs(); ++i) {
+                                if (it->module_ptr->getInput(i)->getState() == state::CHANGED)
                                 {
                                 {
                                     ++(it->changeCounter);
                                     ++(it->changeCounter);
                                 }
                                 }
@@ -132,7 +216,7 @@ namespace mdd {
                     }
                     }
                 }
                 }
             }
             }
-            if (maxIterations != -1 && getProcessorOutput(0)->getValue()[0] >= maxIterations)
+            if (_maxIterations != -1 && processor_outputs[0]->getValue()[0] >= _maxIterations)
             {
             {
                 return state::STATE_ERROR;
                 return state::STATE_ERROR;
             }
             }
@@ -141,7 +225,7 @@ namespace mdd {
     }
     }
 
 
     std::shared_ptr<IOutput> ProcessorStandard::getIteration(){
     std::shared_ptr<IOutput> ProcessorStandard::getIteration(){
-        return getProcessorOutput(0);
+        return processor_outputs[0];
     }
     }
     ProcessorStandard::module_priority::module_priority(std::shared_ptr<IModule> module, size_t inputs, size_t outputs, size_t change)
     ProcessorStandard::module_priority::module_priority(std::shared_ptr<IModule> module, size_t inputs, size_t outputs, size_t change)
     {
     {

+ 38 - 0
lib/src/Registration.cpp

@@ -0,0 +1,38 @@
+
+#include "Registration.h"
+#include <map>
+#include <string>
+#include "IGenerator.h"
+
+#include "ModuleHTTP.cpp"
+#include "ModuleMath.cpp"
+#include "ModuleMerge.cpp"
+//#include "ModuleSplitt.cpp"
+#include "ModuleSQL.cpp"
+#include "ModuleSwitch.cpp"
+
+#include "ProcessorStandard.cpp"
+
+namespace mdd
+{
+	Registration::Registration()
+	{
+		REGISTER(ModuleHTTP);
+		REGISTER(ModuleMath);
+		REGISTER(ModuleMerge);
+		//REGISTER(ModuleSplitt);
+		REGISTER(ModuleSQL);
+		REGISTER(ModuleSwitch);
+
+		REGISTER(ProcessorStandard);
+	}
+	IModule::Ptr Registration::generateModule(const std::string& name)
+	{
+		auto it = _gens.find(name);
+		if (it != _gens.end())
+		{
+			return it->second->generate();
+		}
+		return nullptr;
+	}
+}

+ 2 - 0
lib/test/CMakeLists.txt

@@ -1,11 +1,13 @@
 add_executable(mdd_lib_test
 add_executable(mdd_lib_test
 	test_Ansys.cpp
 	test_Ansys.cpp
 	test_Connector
 	test_Connector
+	test_Input.cpp
         test_ModuleHTTP.cpp
         test_ModuleHTTP.cpp
         test_ModuleMath.cpp
         test_ModuleMath.cpp
         test_ModuleSQL.cpp
         test_ModuleSQL.cpp
         test_ModuleSwitch.cpp
         test_ModuleSwitch.cpp
 	test_OptimizerEvolutionary.cpp
 	test_OptimizerEvolutionary.cpp
+	test_Output.cpp
         test_ProcessorStandard.cpp
         test_ProcessorStandard.cpp
         )
         )
 target_link_libraries(mdd_lib_test gtest gtest_main ${PROJECT_NAME})
 target_link_libraries(mdd_lib_test gtest gtest_main ${PROJECT_NAME})

lib/include/ModuleSplitt.h → lib/test/test_Input.cpp


+ 26 - 9
lib/test/test_ModuleMath.cpp

@@ -1,6 +1,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 #include <json.hpp>
 #include <json.hpp>
-#include <Generator.h>
+//#include <Generator.h>
+#include <Registration.h>
 //#define private public
 //#define private public
 
 
 //cd cmake-build-debug/lib/test
 //cd cmake-build-debug/lib/test
@@ -10,20 +11,33 @@
 
 
 
 
 using namespace mdd;
 using namespace mdd;
+auto regi = Registration();
+
+TEST(ModuleMath, Create) {
+    IModule::Ptr mod = regi.generateModule("ModuleMath");
+
+    auto input = mod->getInput(0);
+    EXPECT_FLOAT_EQ(input->getValue()[0], 1.0);
+
+    input = mod->getInput(1);
+    EXPECT_FLOAT_EQ(input->getValue()[0], 1.0);
+
+    auto output = mod->getOutput(0);
+    EXPECT_FLOAT_EQ(output->getValue()[0], 1.0);
+    int i = 0;
+}
+
 TEST(ModuleMath, INT_PLUS_INT){
 TEST(ModuleMath, INT_PLUS_INT){
-    
-    auto generators = GetGenerators();
-    IModule::Ptr mod = generators["mdd::ModuleMath"]->Generate();
-    mod->configure(mod->getBaseConfiguration());
+    IModule::Ptr mod = regi.generateModule("ModuleMath");
+    auto config = mod->getBaseConfiguration();
+    mod->configure(config);
     mod->update();
     mod->update();
-    auto ids = mod->getOutputIDs();
-    auto id = ids[0];
-    auto output = mod->getOutput(id);
+    auto output = mod->getOutput(0);
     auto res = output->getValue();
     auto res = output->getValue();
     EXPECT_FLOAT_EQ(res[0], 2.0);
     EXPECT_FLOAT_EQ(res[0], 2.0);
 }
 }
 
 
-
+/*
 TEST(ModuleMath, FLOAT_PLUS_FLOAT){
 TEST(ModuleMath, FLOAT_PLUS_FLOAT){
     IModule::Ptr test = GetGenerators()["mdd::ModuleMath"]->Generate();
     IModule::Ptr test = GetGenerators()["mdd::ModuleMath"]->Generate();
     test->configure(test->getBaseConfiguration());
     test->configure(test->getBaseConfiguration());
@@ -33,6 +47,7 @@ TEST(ModuleMath, FLOAT_PLUS_FLOAT){
 
 
     EXPECT_FLOAT_EQ(test->getOutput(test->getOutputIDs()[0])->getValue()[0], 4.375);
     EXPECT_FLOAT_EQ(test->getOutput(test->getOutputIDs()[0])->getValue()[0], 4.375);
 }
 }
+//*/
 /*
 /*
 TEST(ModuleMath, FLOAT_PLUS_FLOAT_HARDER){
 TEST(ModuleMath, FLOAT_PLUS_FLOAT_HARDER){
     ModuleMath test = ModuleMath();
     ModuleMath test = ModuleMath();
@@ -82,6 +97,7 @@ TEST(ModuleMath, ARRAY_MINUS_ARRAY){
     EXPECT_EQ(test.getOutput(test.getOutputIDs()[0])->getValue(), expect);
     EXPECT_EQ(test.getOutput(test.getOutputIDs()[0])->getValue(), expect);
 }
 }
 */
 */
+/*
 TEST(ModuleMath, ARRAY_MAL_ARRAY){
 TEST(ModuleMath, ARRAY_MAL_ARRAY){
     IModule::Ptr test = GetGenerators()["mdd::ModuleMath"]->Generate();
     IModule::Ptr test = GetGenerators()["mdd::ModuleMath"]->Generate();
 
 
@@ -99,6 +115,7 @@ TEST(ModuleMath, ARRAY_MAL_ARRAY){
 
 
     EXPECT_EQ(test->getOutput(test->getOutputIDs()[0])->getValue(), expect);
     EXPECT_EQ(test->getOutput(test->getOutputIDs()[0])->getValue(), expect);
 }
 }
+//*/
 /*
 /*
 TEST(ModuleMath, ARRAY_DURCH_ARRAY){
 TEST(ModuleMath, ARRAY_DURCH_ARRAY){
     ModuleMath test = ModuleMath(MathOperation::DIVIDE);
     ModuleMath test = ModuleMath(MathOperation::DIVIDE);

+ 14 - 0
lib/test/test_Output.cpp

@@ -0,0 +1,14 @@
+#include <gtest/gtest.h>
+#include <json.hpp>
+#include <httplib.h>
+#include <Output.h>
+
+
+using namespace mdd;
+
+TEST(Output, setValue) {
+    std::shared_ptr<Output> out_ptr = std::make_shared<Output>("TEST", 0, std::vector<double>{0});
+    EXPECT_FLOAT_EQ(out_ptr->getValue()[0], 0.0);
+    out_ptr->setValue(std::vector<double>{1});
+    EXPECT_FLOAT_EQ(out_ptr->getValue()[0], 1.0);
+}

+ 179 - 0
thirdparty/googletest/BUILD.bazel

@@ -0,0 +1,179 @@
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#   Bazel Build for Google C++ Testing Framework(Google Test)
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+config_setting(
+    name = "windows",
+    constraint_values = ["@bazel_tools//platforms:windows"],
+)
+
+config_setting(
+    name = "has_absl",
+    values = {"define": "absl=1"},
+)
+
+# Library that defines the FRIEND_TEST macro.
+cc_library(
+    name = "gtest_prod",
+    hdrs = ["googletest/include/gtest/gtest_prod.h"],
+    includes = ["googletest/include"],
+)
+
+# Google Test including Google Mock
+cc_library(
+    name = "gtest",
+    srcs = glob(
+        include = [
+            "googletest/src/*.cc",
+            "googletest/src/*.h",
+            "googletest/include/gtest/**/*.h",
+            "googlemock/src/*.cc",
+            "googlemock/include/gmock/**/*.h",
+        ],
+        exclude = [
+            "googletest/src/gtest-all.cc",
+            "googletest/src/gtest_main.cc",
+            "googlemock/src/gmock-all.cc",
+            "googlemock/src/gmock_main.cc",
+        ],
+    ),
+    hdrs = glob([
+        "googletest/include/gtest/*.h",
+        "googlemock/include/gmock/*.h",
+    ]),
+    copts = select({
+        ":windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    defines = select({
+        ":has_absl": ["GTEST_HAS_ABSL=1"],
+        "//conditions:default": [],
+    }),
+    features = select({
+        ":windows": ["windows_export_all_symbols"],
+        "//conditions:default": [],
+    }),
+    includes = [
+        "googlemock",
+        "googlemock/include",
+        "googletest",
+        "googletest/include",
+    ],
+    linkopts = select({
+        ":windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    deps = select({
+        ":has_absl": [
+            "@com_google_absl//absl/debugging:failure_signal_handler",
+            "@com_google_absl//absl/debugging:stacktrace",
+            "@com_google_absl//absl/debugging:symbolize",
+            "@com_google_absl//absl/strings",
+            "@com_google_absl//absl/types:optional",
+            "@com_google_absl//absl/types:variant",
+        ],
+        "//conditions:default": [],
+    }),
+)
+
+cc_library(
+    name = "gtest_main",
+    srcs = ["googlemock/src/gmock_main.cc"],
+    features = select({
+        ":windows": ["windows_export_all_symbols"],
+        "//conditions:default": [],
+    }),
+    deps = [":gtest"],
+)
+
+# The following rules build samples of how to use gTest.
+cc_library(
+    name = "gtest_sample_lib",
+    srcs = [
+        "googletest/samples/sample1.cc",
+        "googletest/samples/sample2.cc",
+        "googletest/samples/sample4.cc",
+    ],
+    hdrs = [
+        "googletest/samples/prime_tables.h",
+        "googletest/samples/sample1.h",
+        "googletest/samples/sample2.h",
+        "googletest/samples/sample3-inl.h",
+        "googletest/samples/sample4.h",
+    ],
+    features = select({
+        ":windows": ["windows_export_all_symbols"],
+        "//conditions:default": [],
+    }),
+)
+
+cc_test(
+    name = "gtest_samples",
+    size = "small",
+    # All Samples except:
+    #   sample9 (main)
+    #   sample10 (main and takes a command line option and needs to be separate)
+    srcs = [
+        "googletest/samples/sample1_unittest.cc",
+        "googletest/samples/sample2_unittest.cc",
+        "googletest/samples/sample3_unittest.cc",
+        "googletest/samples/sample4_unittest.cc",
+        "googletest/samples/sample5_unittest.cc",
+        "googletest/samples/sample6_unittest.cc",
+        "googletest/samples/sample7_unittest.cc",
+        "googletest/samples/sample8_unittest.cc",
+    ],
+    linkstatic = 0,
+    deps = [
+        "gtest_sample_lib",
+        ":gtest_main",
+    ],
+)
+
+cc_test(
+    name = "sample9_unittest",
+    size = "small",
+    srcs = ["googletest/samples/sample9_unittest.cc"],
+    deps = [":gtest"],
+)
+
+cc_test(
+    name = "sample10_unittest",
+    size = "small",
+    srcs = ["googletest/samples/sample10_unittest.cc"],
+    deps = [":gtest"],
+)

+ 37 - 0
thirdparty/googletest/ci/build-linux-bazel.sh

@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -e
+
+bazel version
+bazel build --curses=no //...:all
+bazel test --curses=no //...:all
+bazel test --curses=no //...:all --define absl=1

+ 2 - 0
thirdparty/googletest/ci/build-platformio.sh

@@ -0,0 +1,2 @@
+# run PlatformIO builds
+platformio run

+ 49 - 0
thirdparty/googletest/ci/install-linux.sh

@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -eu
+
+if [ "${TRAVIS_OS_NAME}" != linux ]; then
+    echo "Not a Linux build; skipping installation"
+    exit 0
+fi
+
+
+if [ "${TRAVIS_SUDO}" = "true" ]; then
+    echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
+        sudo tee /etc/apt/sources.list.d/bazel.list
+    curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
+    sudo apt-get update && sudo apt-get install -y bazel gcc-4.9 g++-4.9 clang-3.9
+elif [ "${CXX}" = "clang++" ]; then
+    # Use ccache, assuming $HOME/bin is in the path, which is true in the Travis build environment.
+    ln -sf /usr/bin/ccache $HOME/bin/${CXX};
+    ln -sf /usr/bin/ccache $HOME/bin/${CC};
+fi

+ 40 - 0
thirdparty/googletest/ci/install-osx.sh

@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -eu
+
+if [ "${TRAVIS_OS_NAME}" != "osx" ]; then
+    echo "Not a macOS build; skipping installation"
+    exit 0
+fi
+
+brew update
+brew install ccache gcc@4.9

+ 5 - 0
thirdparty/googletest/ci/install-platformio.sh

@@ -0,0 +1,5 @@
+# install PlatformIO
+sudo pip install -U platformio
+
+# update PlatformIO
+platformio update

文件差異過大導致無法顯示
+ 1985 - 0
thirdparty/googletest/googlemock/include/gmock/gmock-spec-builders.h


+ 888 - 0
thirdparty/googletest/googlemock/src/gmock-spec-builders.cc

@@ -0,0 +1,888 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Google Mock - a framework for writing C++ mock classes.
+//
+// This file implements the spec builder syntax (ON_CALL and
+// EXPECT_CALL).
+
+#include "gmock/gmock-spec-builders.h"
+
+#include <stdlib.h>
+#include <iostream>  // NOLINT
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
+# include <unistd.h>  // NOLINT
+#endif
+
+// Silence C4800 (C4800: 'int *const ': forcing value
+// to bool 'true' or 'false') for MSVC 15
+#ifdef _MSC_VER
+#if _MSC_VER == 1900
+#  pragma warning(push)
+#  pragma warning(disable:4800)
+#endif
+#endif
+
+namespace testing {
+namespace internal {
+
+// Protects the mock object registry (in class Mock), all function
+// mockers, and all expectations.
+GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex);
+
+// Logs a message including file and line number information.
+GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
+                                const char* file, int line,
+                                const std::string& message) {
+  ::std::ostringstream s;
+  s << file << ":" << line << ": " << message << ::std::endl;
+  Log(severity, s.str(), 0);
+}
+
+// Constructs an ExpectationBase object.
+ExpectationBase::ExpectationBase(const char* a_file, int a_line,
+                                 const std::string& a_source_text)
+    : file_(a_file),
+      line_(a_line),
+      source_text_(a_source_text),
+      cardinality_specified_(false),
+      cardinality_(Exactly(1)),
+      call_count_(0),
+      retired_(false),
+      extra_matcher_specified_(false),
+      repeated_action_specified_(false),
+      retires_on_saturation_(false),
+      last_clause_(kNone),
+      action_count_checked_(false) {}
+
+// Destructs an ExpectationBase object.
+ExpectationBase::~ExpectationBase() {}
+
+// Explicitly specifies the cardinality of this expectation.  Used by
+// the subclasses to implement the .Times() clause.
+void ExpectationBase::SpecifyCardinality(const Cardinality& a_cardinality) {
+  cardinality_specified_ = true;
+  cardinality_ = a_cardinality;
+}
+
+// Retires all pre-requisites of this expectation.
+void ExpectationBase::RetireAllPreRequisites()
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+  if (is_retired()) {
+    // We can take this short-cut as we never retire an expectation
+    // until we have retired all its pre-requisites.
+    return;
+  }
+
+  ::std::vector<ExpectationBase*> expectations(1, this);
+  while (!expectations.empty()) {
+    ExpectationBase* exp = expectations.back();
+    expectations.pop_back();
+
+    for (ExpectationSet::const_iterator it =
+             exp->immediate_prerequisites_.begin();
+         it != exp->immediate_prerequisites_.end(); ++it) {
+      ExpectationBase* next = it->expectation_base().get();
+      if (!next->is_retired()) {
+        next->Retire();
+        expectations.push_back(next);
+      }
+    }
+  }
+}
+
+// Returns true if and only if all pre-requisites of this expectation
+// have been satisfied.
+bool ExpectationBase::AllPrerequisitesAreSatisfied() const
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+  g_gmock_mutex.AssertHeld();
+  ::std::vector<const ExpectationBase*> expectations(1, this);
+  while (!expectations.empty()) {
+    const ExpectationBase* exp = expectations.back();
+    expectations.pop_back();
+
+    for (ExpectationSet::const_iterator it =
+             exp->immediate_prerequisites_.begin();
+         it != exp->immediate_prerequisites_.end(); ++it) {
+      const ExpectationBase* next = it->expectation_base().get();
+      if (!next->IsSatisfied()) return false;
+      expectations.push_back(next);
+    }
+  }
+  return true;
+}
+
+// Adds unsatisfied pre-requisites of this expectation to 'result'.
+void ExpectationBase::FindUnsatisfiedPrerequisites(ExpectationSet* result) const
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+  g_gmock_mutex.AssertHeld();
+  ::std::vector<const ExpectationBase*> expectations(1, this);
+  while (!expectations.empty()) {
+    const ExpectationBase* exp = expectations.back();
+    expectations.pop_back();
+
+    for (ExpectationSet::const_iterator it =
+             exp->immediate_prerequisites_.begin();
+         it != exp->immediate_prerequisites_.end(); ++it) {
+      const ExpectationBase* next = it->expectation_base().get();
+
+      if (next->IsSatisfied()) {
+        // If *it is satisfied and has a call count of 0, some of its
+        // pre-requisites may not be satisfied yet.
+        if (next->call_count_ == 0) {
+          expectations.push_back(next);
+        }
+      } else {
+        // Now that we know next is unsatisfied, we are not so interested
+        // in whether its pre-requisites are satisfied.  Therefore we
+        // don't iterate into it here.
+        *result += *it;
+      }
+    }
+  }
+}
+
+// Describes how many times a function call matching this
+// expectation has occurred.
+void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+  g_gmock_mutex.AssertHeld();
+
+  // Describes how many times the function is expected to be called.
+  *os << "         Expected: to be ";
+  cardinality().DescribeTo(os);
+  *os << "\n           Actual: ";
+  Cardinality::DescribeActualCallCountTo(call_count(), os);
+
+  // Describes the state of the expectation (e.g. is it satisfied?
+  // is it active?).
+  *os << " - " << (IsOverSaturated() ? "over-saturated" :
+                   IsSaturated() ? "saturated" :
+                   IsSatisfied() ? "satisfied" : "unsatisfied")
+      << " and "
+      << (is_retired() ? "retired" : "active");
+}
+
+// Checks the action count (i.e. the number of WillOnce() and
+// WillRepeatedly() clauses) against the cardinality if this hasn't
+// been done before.  Prints a warning if there are too many or too
+// few actions.
+void ExpectationBase::CheckActionCountIfNotDone() const
+    GTEST_LOCK_EXCLUDED_(mutex_) {
+  bool should_check = false;
+  {
+    MutexLock l(&mutex_);
+    if (!action_count_checked_) {
+      action_count_checked_ = true;
+      should_check = true;
+    }
+  }
+
+  if (should_check) {
+    if (!cardinality_specified_) {
+      // The cardinality was inferred - no need to check the action
+      // count against it.
+      return;
+    }
+
+    // The cardinality was explicitly specified.
+    const int action_count = static_cast<int>(untyped_actions_.size());
+    const int upper_bound = cardinality().ConservativeUpperBound();
+    const int lower_bound = cardinality().ConservativeLowerBound();
+    bool too_many;  // True if there are too many actions, or false
+    // if there are too few.
+    if (action_count > upper_bound ||
+        (action_count == upper_bound && repeated_action_specified_)) {
+      too_many = true;
+    } else if (0 < action_count && action_count < lower_bound &&
+               !repeated_action_specified_) {
+      too_many = false;
+    } else {
+      return;
+    }
+
+    ::std::stringstream ss;
+    DescribeLocationTo(&ss);
+    ss << "Too " << (too_many ? "many" : "few")
+       << " actions specified in " << source_text() << "...\n"
+       << "Expected to be ";
+    cardinality().DescribeTo(&ss);
+    ss << ", but has " << (too_many ? "" : "only ")
+       << action_count << " WillOnce()"
+       << (action_count == 1 ? "" : "s");
+    if (repeated_action_specified_) {
+      ss << " and a WillRepeatedly()";
+    }
+    ss << ".";
+    Log(kWarning, ss.str(), -1);  // -1 means "don't print stack trace".
+  }
+}
+
+// Implements the .Times() clause.
+void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) {
+  if (last_clause_ == kTimes) {
+    ExpectSpecProperty(false,
+                       ".Times() cannot appear "
+                       "more than once in an EXPECT_CALL().");
+  } else {
+    ExpectSpecProperty(last_clause_ < kTimes,
+                       ".Times() cannot appear after "
+                       ".InSequence(), .WillOnce(), .WillRepeatedly(), "
+                       "or .RetiresOnSaturation().");
+  }
+  last_clause_ = kTimes;
+
+  SpecifyCardinality(a_cardinality);
+}
+
+// Points to the implicit sequence introduced by a living InSequence
+// object (if any) in the current thread or NULL.
+GTEST_API_ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
+
+// Reports an uninteresting call (whose description is in msg) in the
+// manner specified by 'reaction'.
+void ReportUninterestingCall(CallReaction reaction, const std::string& msg) {
+  // Include a stack trace only if --gmock_verbose=info is specified.
+  const int stack_frames_to_skip =
+      GMOCK_FLAG(verbose) == kInfoVerbosity ? 3 : -1;
+  switch (reaction) {
+    case kAllow:
+      Log(kInfo, msg, stack_frames_to_skip);
+      break;
+    case kWarn:
+      Log(kWarning,
+          msg +
+              "\nNOTE: You can safely ignore the above warning unless this "
+              "call should not happen.  Do not suppress it by blindly adding "
+              "an EXPECT_CALL() if you don't mean to enforce the call.  "
+              "See "
+              "https://github.com/google/googletest/blob/master/googlemock/"
+              "docs/cook_book.md#"
+              "knowing-when-to-expect for details.\n",
+          stack_frames_to_skip);
+      break;
+    default:  // FAIL
+      Expect(false, nullptr, -1, msg);
+  }
+}
+
+UntypedFunctionMockerBase::UntypedFunctionMockerBase()
+    : mock_obj_(nullptr), name_("") {}
+
+UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {}
+
+// Sets the mock object this mock method belongs to, and registers
+// this information in the global mock registry.  Will be called
+// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
+// method.
+void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+  {
+    MutexLock l(&g_gmock_mutex);
+    mock_obj_ = mock_obj;
+  }
+  Mock::Register(mock_obj, this);
+}
+
+// Sets the mock object this mock method belongs to, and sets the name
+// of the mock function.  Will be called upon each invocation of this
+// mock function.
+void UntypedFunctionMockerBase::SetOwnerAndName(const void* mock_obj,
+                                                const char* name)
+    GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+  // We protect name_ under g_gmock_mutex in case this mock function
+  // is called from two threads concurrently.
+  MutexLock l(&g_gmock_mutex);
+  mock_obj_ = mock_obj;
+  name_ = name;
+}
+
+// Returns the name of the function being mocked.  Must be called
+// after RegisterOwner() or SetOwnerAndName() has been called.
+const void* UntypedFunctionMockerBase::MockObject() const
+    GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+  const void* mock_obj;
+  {
+    // We protect mock_obj_ under g_gmock_mutex in case this mock
+    // function is called from two threads concurrently.
+    MutexLock l(&g_gmock_mutex);
+    Assert(mock_obj_ != nullptr, __FILE__, __LINE__,
+           "MockObject() must not be called before RegisterOwner() or "
+           "SetOwnerAndName() has been called.");
+    mock_obj = mock_obj_;
+  }
+  return mock_obj;
+}
+
+// Returns the name of this mock method.  Must be called after
+// SetOwnerAndName() has been called.
+const char* UntypedFunctionMockerBase::Name() const
+    GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+  const char* name;
+  {
+    // We protect name_ under g_gmock_mutex in case this mock
+    // function is called from two threads concurrently.
+    MutexLock l(&g_gmock_mutex);
+    Assert(name_ != nullptr, __FILE__, __LINE__,
+           "Name() must not be called before SetOwnerAndName() has "
+           "been called.");
+    name = name_;
+  }
+  return name;
+}
+
+// Calculates the result of invoking this mock function with the given
+// arguments, prints it, and returns it.  The caller is responsible
+// for deleting the result.
+UntypedActionResultHolderBase* UntypedFunctionMockerBase::UntypedInvokeWith(
+    void* const untyped_args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
+  // See the definition of untyped_expectations_ for why access to it
+  // is unprotected here.
+  if (untyped_expectations_.size() == 0) {
+    // No expectation is set on this mock method - we have an
+    // uninteresting call.
+
+    // We must get Google Mock's reaction on uninteresting calls
+    // made on this mock object BEFORE performing the action,
+    // because the action may DELETE the mock object and make the
+    // following expression meaningless.
+    const CallReaction reaction =
+        Mock::GetReactionOnUninterestingCalls(MockObject());
+
+    // True if and only if we need to print this call's arguments and return
+    // value.  This definition must be kept in sync with
+    // the behavior of ReportUninterestingCall().
+    const bool need_to_report_uninteresting_call =
+        // If the user allows this uninteresting call, we print it
+        // only when they want informational messages.
+        reaction == kAllow ? LogIsVisible(kInfo) :
+                           // If the user wants this to be a warning, we print
+                           // it only when they want to see warnings.
+            reaction == kWarn
+                ? LogIsVisible(kWarning)
+                :
+                // Otherwise, the user wants this to be an error, and we
+                // should always print detailed information in the error.
+                true;
+
+    if (!need_to_report_uninteresting_call) {
+      // Perform the action without printing the call information.
+      return this->UntypedPerformDefaultAction(
+          untyped_args, "Function call: " + std::string(Name()));
+    }
+
+    // Warns about the uninteresting call.
+    ::std::stringstream ss;
+    this->UntypedDescribeUninterestingCall(untyped_args, &ss);
+
+    // Calculates the function result.
+    UntypedActionResultHolderBase* const result =
+        this->UntypedPerformDefaultAction(untyped_args, ss.str());
+
+    // Prints the function result.
+    if (result != nullptr) result->PrintAsActionResult(&ss);
+
+    ReportUninterestingCall(reaction, ss.str());
+    return result;
+  }
+
+  bool is_excessive = false;
+  ::std::stringstream ss;
+  ::std::stringstream why;
+  ::std::stringstream loc;
+  const void* untyped_action = nullptr;
+
+  // The UntypedFindMatchingExpectation() function acquires and
+  // releases g_gmock_mutex.
+  const ExpectationBase* const untyped_expectation =
+      this->UntypedFindMatchingExpectation(
+          untyped_args, &untyped_action, &is_excessive,
+          &ss, &why);
+  const bool found = untyped_expectation != nullptr;
+
+  // True if and only if we need to print the call's arguments
+  // and return value.
+  // This definition must be kept in sync with the uses of Expect()
+  // and Log() in this function.
+  const bool need_to_report_call =
+      !found || is_excessive || LogIsVisible(kInfo);
+  if (!need_to_report_call) {
+    // Perform the action without printing the call information.
+    return untyped_action == nullptr
+               ? this->UntypedPerformDefaultAction(untyped_args, "")
+               : this->UntypedPerformAction(untyped_action, untyped_args);
+  }
+
+  ss << "    Function call: " << Name();
+  this->UntypedPrintArgs(untyped_args, &ss);
+
+  // In case the action deletes a piece of the expectation, we
+  // generate the message beforehand.
+  if (found && !is_excessive) {
+    untyped_expectation->DescribeLocationTo(&loc);
+  }
+
+  UntypedActionResultHolderBase* const result =
+      untyped_action == nullptr
+          ? this->UntypedPerformDefaultAction(untyped_args, ss.str())
+          : this->UntypedPerformAction(untyped_action, untyped_args);
+  if (result != nullptr) result->PrintAsActionResult(&ss);
+  ss << "\n" << why.str();
+
+  if (!found) {
+    // No expectation matches this call - reports a failure.
+    Expect(false, nullptr, -1, ss.str());
+  } else if (is_excessive) {
+    // We had an upper-bound violation and the failure message is in ss.
+    Expect(false, untyped_expectation->file(),
+           untyped_expectation->line(), ss.str());
+  } else {
+    // We had an expected call and the matching expectation is
+    // described in ss.
+    Log(kInfo, loc.str() + ss.str(), 2);
+  }
+
+  return result;
+}
+
+// Returns an Expectation object that references and co-owns exp,
+// which must be an expectation on this mock function.
+Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) {
+  // See the definition of untyped_expectations_ for why access to it
+  // is unprotected here.
+  for (UntypedExpectations::const_iterator it =
+           untyped_expectations_.begin();
+       it != untyped_expectations_.end(); ++it) {
+    if (it->get() == exp) {
+      return Expectation(*it);
+    }
+  }
+
+  Assert(false, __FILE__, __LINE__, "Cannot find expectation.");
+  return Expectation();
+  // The above statement is just to make the code compile, and will
+  // never be executed.
+}
+
+// Verifies that all expectations on this mock function have been
+// satisfied.  Reports one or more Google Test non-fatal failures
+// and returns false if not.
+bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked()
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
+  g_gmock_mutex.AssertHeld();
+  bool expectations_met = true;
+  for (UntypedExpectations::const_iterator it =
+           untyped_expectations_.begin();
+       it != untyped_expectations_.end(); ++it) {
+    ExpectationBase* const untyped_expectation = it->get();
+    if (untyped_expectation->IsOverSaturated()) {
+      // There was an upper-bound violation.  Since the error was
+      // already reported when it occurred, there is no need to do
+      // anything here.
+      expectations_met = false;
+    } else if (!untyped_expectation->IsSatisfied()) {
+      expectations_met = false;
+      ::std::stringstream ss;
+      ss  << "Actual function call count doesn't match "
+          << untyped_expectation->source_text() << "...\n";
+      // No need to show the source file location of the expectation
+      // in the description, as the Expect() call that follows already
+      // takes care of it.
+      untyped_expectation->MaybeDescribeExtraMatcherTo(&ss);
+      untyped_expectation->DescribeCallCountTo(&ss);
+      Expect(false, untyped_expectation->file(),
+             untyped_expectation->line(), ss.str());
+    }
+  }
+
+  // Deleting our expectations may trigger other mock objects to be deleted, for
+  // example if an action contains a reference counted smart pointer to that
+  // mock object, and that is the last reference. So if we delete our
+  // expectations within the context of the global mutex we may deadlock when
+  // this method is called again. Instead, make a copy of the set of
+  // expectations to delete, clear our set within the mutex, and then clear the
+  // copied set outside of it.
+  UntypedExpectations expectations_to_delete;
+  untyped_expectations_.swap(expectations_to_delete);
+
+  g_gmock_mutex.Unlock();
+  expectations_to_delete.clear();
+  g_gmock_mutex.Lock();
+
+  return expectations_met;
+}
+
+CallReaction intToCallReaction(int mock_behavior) {
+  if (mock_behavior >= kAllow && mock_behavior <= kFail) {
+    return static_cast<internal::CallReaction>(mock_behavior);
+  }
+  return kWarn;
+}
+
+}  // namespace internal
+
+// Class Mock.
+
+namespace {
+
+typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
+
+// The current state of a mock object.  Such information is needed for
+// detecting leaked mock objects and explicitly verifying a mock's
+// expectations.
+struct MockObjectState {
+  MockObjectState()
+      : first_used_file(nullptr), first_used_line(-1), leakable(false) {}
+
+  // Where in the source file an ON_CALL or EXPECT_CALL is first
+  // invoked on this mock object.
+  const char* first_used_file;
+  int first_used_line;
+  ::std::string first_used_test_suite;
+  ::std::string first_used_test;
+  bool leakable;  // true if and only if it's OK to leak the object.
+  FunctionMockers function_mockers;  // All registered methods of the object.
+};
+
+// A global registry holding the state of all mock objects that are
+// alive.  A mock object is added to this registry the first time
+// Mock::AllowLeak(), ON_CALL(), or EXPECT_CALL() is called on it.  It
+// is removed from the registry in the mock object's destructor.
+class MockObjectRegistry {
+ public:
+  // Maps a mock object (identified by its address) to its state.
+  typedef std::map<const void*, MockObjectState> StateMap;
+
+  // This destructor will be called when a program exits, after all
+  // tests in it have been run.  By then, there should be no mock
+  // object alive.  Therefore we report any living object as test
+  // failure, unless the user explicitly asked us to ignore it.
+  ~MockObjectRegistry() {
+    if (!GMOCK_FLAG(catch_leaked_mocks))
+      return;
+
+    int leaked_count = 0;
+    for (StateMap::const_iterator it = states_.begin(); it != states_.end();
+         ++it) {
+      if (it->second.leakable)  // The user said it's fine to leak this object.
+        continue;
+
+      // FIXME: Print the type of the leaked object.
+      // This can help the user identify the leaked object.
+      std::cout << "\n";
+      const MockObjectState& state = it->second;
+      std::cout << internal::FormatFileLocation(state.first_used_file,
+                                                state.first_used_line);
+      std::cout << " ERROR: this mock object";
+      if (state.first_used_test != "") {
+        std::cout << " (used in test " << state.first_used_test_suite << "."
+                  << state.first_used_test << ")";
+      }
+      std::cout << " should be deleted but never is. Its address is @"
+           << it->first << ".";
+      leaked_count++;
+    }
+    if (leaked_count > 0) {
+      std::cout << "\nERROR: " << leaked_count << " leaked mock "
+                << (leaked_count == 1 ? "object" : "objects")
+                << " found at program exit. Expectations on a mock object is "
+                   "verified when the object is destructed. Leaking a mock "
+                   "means that its expectations aren't verified, which is "
+                   "usually a test bug. If you really intend to leak a mock, "
+                   "you can suppress this error using "
+                   "testing::Mock::AllowLeak(mock_object), or you may use a "
+                   "fake or stub instead of a mock.\n";
+      std::cout.flush();
+      ::std::cerr.flush();
+      // RUN_ALL_TESTS() has already returned when this destructor is
+      // called.  Therefore we cannot use the normal Google Test
+      // failure reporting mechanism.
+      _exit(1);  // We cannot call exit() as it is not reentrant and
+                 // may already have been called.
+    }
+  }
+
+  StateMap& states() { return states_; }
+
+ private:
+  StateMap states_;
+};
+
+// Protected by g_gmock_mutex.
+MockObjectRegistry g_mock_object_registry;
+
+// Maps a mock object to the reaction Google Mock should have when an
+// uninteresting method is called.  Protected by g_gmock_mutex.
+std::map<const void*, internal::CallReaction> g_uninteresting_call_reaction;
+
+// Sets the reaction Google Mock should have when an uninteresting
+// method of the given mock object is called.
+void SetReactionOnUninterestingCalls(const void* mock_obj,
+                                     internal::CallReaction reaction)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  g_uninteresting_call_reaction[mock_obj] = reaction;
+}
+
+}  // namespace
+
+// Tells Google Mock to allow uninteresting calls on the given mock
+// object.
+void Mock::AllowUninterestingCalls(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  SetReactionOnUninterestingCalls(mock_obj, internal::kAllow);
+}
+
+// Tells Google Mock to warn the user about uninteresting calls on the
+// given mock object.
+void Mock::WarnUninterestingCalls(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  SetReactionOnUninterestingCalls(mock_obj, internal::kWarn);
+}
+
+// Tells Google Mock to fail uninteresting calls on the given mock
+// object.
+void Mock::FailUninterestingCalls(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  SetReactionOnUninterestingCalls(mock_obj, internal::kFail);
+}
+
+// Tells Google Mock the given mock object is being destroyed and its
+// entry in the call-reaction table should be removed.
+void Mock::UnregisterCallReaction(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  g_uninteresting_call_reaction.erase(mock_obj);
+}
+
+// Returns the reaction Google Mock will have on uninteresting calls
+// made on the given mock object.
+internal::CallReaction Mock::GetReactionOnUninterestingCalls(
+    const void* mock_obj)
+        GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  return (g_uninteresting_call_reaction.count(mock_obj) == 0) ?
+      internal::intToCallReaction(GMOCK_FLAG(default_mock_behavior)) :
+      g_uninteresting_call_reaction[mock_obj];
+}
+
+// Tells Google Mock to ignore mock_obj when checking for leaked mock
+// objects.
+void Mock::AllowLeak(const void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  g_mock_object_registry.states()[mock_obj].leakable = true;
+}
+
+// Verifies and clears all expectations on the given mock object.  If
+// the expectations aren't satisfied, generates one or more Google
+// Test non-fatal failures and returns false.
+bool Mock::VerifyAndClearExpectations(void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  return VerifyAndClearExpectationsLocked(mock_obj);
+}
+
+// Verifies all expectations on the given mock object and clears its
+// default actions and expectations.  Returns true if and only if the
+// verification was successful.
+bool Mock::VerifyAndClear(void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  ClearDefaultActionsLocked(mock_obj);
+  return VerifyAndClearExpectationsLocked(mock_obj);
+}
+
+// Verifies and clears all expectations on the given mock object.  If
+// the expectations aren't satisfied, generates one or more Google
+// Test non-fatal failures and returns false.
+bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj)
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+  internal::g_gmock_mutex.AssertHeld();
+  if (g_mock_object_registry.states().count(mock_obj) == 0) {
+    // No EXPECT_CALL() was set on the given mock object.
+    return true;
+  }
+
+  // Verifies and clears the expectations on each mock method in the
+  // given mock object.
+  bool expectations_met = true;
+  FunctionMockers& mockers =
+      g_mock_object_registry.states()[mock_obj].function_mockers;
+  for (FunctionMockers::const_iterator it = mockers.begin();
+       it != mockers.end(); ++it) {
+    if (!(*it)->VerifyAndClearExpectationsLocked()) {
+      expectations_met = false;
+    }
+  }
+
+  // We don't clear the content of mockers, as they may still be
+  // needed by ClearDefaultActionsLocked().
+  return expectations_met;
+}
+
+bool Mock::IsNaggy(void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kWarn;
+}
+bool Mock::IsNice(void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kAllow;
+}
+bool Mock::IsStrict(void* mock_obj)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kFail;
+}
+
+// Registers a mock object and a mock method it owns.
+void Mock::Register(const void* mock_obj,
+                    internal::UntypedFunctionMockerBase* mocker)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker);
+}
+
+// Tells Google Mock where in the source code mock_obj is used in an
+// ON_CALL or EXPECT_CALL.  In case mock_obj is leaked, this
+// information helps the user identify which object it is.
+void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj,
+                                           const char* file, int line)
+    GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
+  internal::MutexLock l(&internal::g_gmock_mutex);
+  MockObjectState& state = g_mock_object_registry.states()[mock_obj];
+  if (state.first_used_file == nullptr) {
+    state.first_used_file = file;
+    state.first_used_line = line;
+    const TestInfo* const test_info =
+        UnitTest::GetInstance()->current_test_info();
+    if (test_info != nullptr) {
+      state.first_used_test_suite = test_info->test_suite_name();
+      state.first_used_test = test_info->name();
+    }
+  }
+}
+
+// Unregisters a mock method; removes the owning mock object from the
+// registry when the last mock method associated with it has been
+// unregistered.  This is called only in the destructor of
+// FunctionMockerBase.
+void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+  internal::g_gmock_mutex.AssertHeld();
+  for (MockObjectRegistry::StateMap::iterator it =
+           g_mock_object_registry.states().begin();
+       it != g_mock_object_registry.states().end(); ++it) {
+    FunctionMockers& mockers = it->second.function_mockers;
+    if (mockers.erase(mocker) > 0) {
+      // mocker was in mockers and has been just removed.
+      if (mockers.empty()) {
+        g_mock_object_registry.states().erase(it);
+      }
+      return;
+    }
+  }
+}
+
+// Clears all ON_CALL()s set on the given mock object.
+void Mock::ClearDefaultActionsLocked(void* mock_obj)
+    GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
+  internal::g_gmock_mutex.AssertHeld();
+
+  if (g_mock_object_registry.states().count(mock_obj) == 0) {
+    // No ON_CALL() was set on the given mock object.
+    return;
+  }
+
+  // Clears the default actions for each mock method in the given mock
+  // object.
+  FunctionMockers& mockers =
+      g_mock_object_registry.states()[mock_obj].function_mockers;
+  for (FunctionMockers::const_iterator it = mockers.begin();
+       it != mockers.end(); ++it) {
+    (*it)->ClearDefaultActionsLocked();
+  }
+
+  // We don't clear the content of mockers, as they may still be
+  // needed by VerifyAndClearExpectationsLocked().
+}
+
+Expectation::Expectation() {}
+
+Expectation::Expectation(
+    const std::shared_ptr<internal::ExpectationBase>& an_expectation_base)
+    : expectation_base_(an_expectation_base) {}
+
+Expectation::~Expectation() {}
+
+// Adds an expectation to a sequence.
+void Sequence::AddExpectation(const Expectation& expectation) const {
+  if (*last_expectation_ != expectation) {
+    if (last_expectation_->expectation_base() != nullptr) {
+      expectation.expectation_base()->immediate_prerequisites_
+          += *last_expectation_;
+    }
+    *last_expectation_ = expectation;
+  }
+}
+
+// Creates the implicit sequence if there isn't one.
+InSequence::InSequence() {
+  if (internal::g_gmock_implicit_sequence.get() == nullptr) {
+    internal::g_gmock_implicit_sequence.set(new Sequence);
+    sequence_created_ = true;
+  } else {
+    sequence_created_ = false;
+  }
+}
+
+// Deletes the implicit sequence if it was created by the constructor
+// of this object.
+InSequence::~InSequence() {
+  if (sequence_created_) {
+    delete internal::g_gmock_implicit_sequence.get();
+    internal::g_gmock_implicit_sequence.set(nullptr);
+  }
+}
+
+}  // namespace testing
+
+#ifdef _MSC_VER
+#if _MSC_VER == 1900
+#  pragma warning(pop)
+#endif
+#endif

+ 110 - 0
thirdparty/googletest/googlemock/test/BUILD.bazel

@@ -0,0 +1,110 @@
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: misterg@google.com (Gennadiy Civil)
+#
+#   Bazel Build for Google C++ Testing Framework(Google Test)-googlemock
+
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test")
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+licenses(["notice"])
+
+# Tests for GMock itself
+cc_test(
+    name = "gmock_all_test",
+    size = "small",
+    srcs = glob(include = ["gmock-*.cc"]),
+    linkopts = select({
+        "//:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    deps = ["//:gtest"],
+)
+
+# Python tests
+py_library(
+    name = "gmock_test_utils",
+    testonly = 1,
+    srcs = ["gmock_test_utils.py"],
+)
+
+cc_binary(
+    name = "gmock_leak_test_",
+    testonly = 1,
+    srcs = ["gmock_leak_test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+py_test(
+    name = "gmock_leak_test",
+    size = "medium",
+    srcs = ["gmock_leak_test.py"],
+    data = [
+        ":gmock_leak_test_",
+        ":gmock_test_utils",
+    ],
+)
+
+cc_test(
+    name = "gmock_link_test",
+    size = "small",
+    srcs = [
+        "gmock_link2_test.cc",
+        "gmock_link_test.cc",
+        "gmock_link_test.h",
+    ],
+    deps = ["//:gtest_main"],
+)
+
+cc_binary(
+    name = "gmock_output_test_",
+    srcs = ["gmock_output_test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "gmock_output_test",
+    size = "medium",
+    srcs = ["gmock_output_test.py"],
+    data = [
+        ":gmock_output_test_",
+        ":gmock_output_test_golden.txt",
+    ],
+    python_version = "PY2",
+    deps = [":gmock_test_utils"],
+)
+
+cc_test(
+    name = "gmock_test",
+    size = "small",
+    srcs = ["gmock_test.cc"],
+    deps = ["//:gtest_main"],
+)

文件差異過大導致無法顯示
+ 2775 - 0
thirdparty/googletest/googlemock/test/gmock-spec-builders_test.cc


+ 521 - 0
thirdparty/googletest/googletest/test/BUILD.bazel

@@ -0,0 +1,521 @@
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: misterg@google.com (Gennadiy Civil)
+#
+# Bazel BUILD for The Google C++ Testing Framework (Google Test)
+
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test")
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+licenses(["notice"])
+
+#on windows exclude gtest-tuple.h
+cc_test(
+    name = "gtest_all_test",
+    size = "small",
+    srcs = glob(
+        include = [
+            "gtest-*.cc",
+            "googletest-*.cc",
+            "*.h",
+            "googletest/include/gtest/**/*.h",
+        ],
+        exclude = [
+            "gtest-unittest-api_test.cc",
+            "googletest/src/gtest-all.cc",
+            "gtest_all_test.cc",
+            "gtest-death-test_ex_test.cc",
+            "gtest-listener_test.cc",
+            "gtest-unittest-api_test.cc",
+            "googletest-param-test-test.cc",
+            "googletest-catch-exceptions-test_.cc",
+            "googletest-color-test_.cc",
+            "googletest-env-var-test_.cc",
+            "googletest-filter-unittest_.cc",
+            "googletest-break-on-failure-unittest_.cc",
+            "googletest-listener-test.cc",
+            "googletest-output-test_.cc",
+            "googletest-list-tests-unittest_.cc",
+            "googletest-shuffle-test_.cc",
+            "googletest-uninitialized-test_.cc",
+            "googletest-death-test_ex_test.cc",
+            "googletest-param-test-test",
+            "googletest-throw-on-failure-test_.cc",
+            "googletest-param-test-invalid-name1-test_.cc",
+            "googletest-param-test-invalid-name2-test_.cc",
+        ],
+    ) + select({
+        "//:windows": [],
+        "//conditions:default": [],
+    }),
+    copts = select({
+        "//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"],
+        "//conditions:default": ["-DGTEST_USE_OWN_TR1_TUPLE=1"],
+    }),
+    includes = [
+        "googletest",
+        "googletest/include",
+        "googletest/include/internal",
+        "googletest/test",
+    ],
+    linkopts = select({
+        "//:windows": [],
+        "//conditions:default": ["-pthread"],
+    }),
+    deps = ["//:gtest_main"],
+)
+
+# Tests death tests.
+cc_test(
+    name = "googletest-death-test-test",
+    size = "medium",
+    srcs = ["googletest-death-test-test.cc"],
+    deps = ["//:gtest_main"],
+)
+
+cc_test(
+    name = "gtest_test_macro_stack_footprint_test",
+    size = "small",
+    srcs = ["gtest_test_macro_stack_footprint_test.cc"],
+    deps = ["//:gtest"],
+)
+
+#These googletest tests have their own main()
+cc_test(
+    name = "googletest-listener-test",
+    size = "small",
+    srcs = ["googletest-listener-test.cc"],
+    deps = ["//:gtest_main"],
+)
+
+cc_test(
+    name = "gtest-unittest-api_test",
+    size = "small",
+    srcs = [
+        "gtest-unittest-api_test.cc",
+    ],
+    deps = [
+        "//:gtest",
+    ],
+)
+
+cc_test(
+    name = "googletest-param-test-test",
+    size = "small",
+    srcs = [
+        "googletest-param-test-test.cc",
+        "googletest-param-test-test.h",
+        "googletest-param-test2-test.cc",
+    ],
+    deps = ["//:gtest"],
+)
+
+cc_test(
+    name = "gtest_unittest",
+    size = "small",
+    srcs = ["gtest_unittest.cc"],
+    args = ["--heap_check=strict"],
+    shard_count = 2,
+    deps = ["//:gtest_main"],
+)
+
+#  Py tests
+
+py_library(
+    name = "gtest_test_utils",
+    testonly = 1,
+    srcs = ["gtest_test_utils.py"],
+)
+
+cc_binary(
+    name = "gtest_help_test_",
+    testonly = 1,
+    srcs = ["gtest_help_test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+py_test(
+    name = "gtest_help_test",
+    size = "small",
+    srcs = ["gtest_help_test.py"],
+    data = [":gtest_help_test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-output-test_",
+    testonly = 1,
+    srcs = ["googletest-output-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-output-test",
+    size = "small",
+    srcs = ["googletest-output-test.py"],
+    args = select({
+        "//:has_absl": [],
+        "//conditions:default": ["--no_stacktrace_support"],
+    }),
+    data = [
+        "googletest-output-test-golden-lin.txt",
+        ":googletest-output-test_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-color-test_",
+    testonly = 1,
+    srcs = ["googletest-color-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-color-test",
+    size = "small",
+    srcs = ["googletest-color-test.py"],
+    data = [":googletest-color-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-env-var-test_",
+    testonly = 1,
+    srcs = ["googletest-env-var-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-env-var-test",
+    size = "medium",
+    srcs = ["googletest-env-var-test.py"],
+    data = [":googletest-env-var-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-filter-unittest_",
+    testonly = 1,
+    srcs = ["googletest-filter-unittest_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-filter-unittest",
+    size = "medium",
+    srcs = ["googletest-filter-unittest.py"],
+    data = [":googletest-filter-unittest_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-break-on-failure-unittest_",
+    testonly = 1,
+    srcs = ["googletest-break-on-failure-unittest_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-break-on-failure-unittest",
+    size = "small",
+    srcs = ["googletest-break-on-failure-unittest.py"],
+    data = [":googletest-break-on-failure-unittest_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_test(
+    name = "gtest_assert_by_exception_test",
+    size = "small",
+    srcs = ["gtest_assert_by_exception_test.cc"],
+    deps = ["//:gtest"],
+)
+
+cc_binary(
+    name = "googletest-throw-on-failure-test_",
+    testonly = 1,
+    srcs = ["googletest-throw-on-failure-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-throw-on-failure-test",
+    size = "small",
+    srcs = ["googletest-throw-on-failure-test.py"],
+    data = [":googletest-throw-on-failure-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-list-tests-unittest_",
+    testonly = 1,
+    srcs = ["googletest-list-tests-unittest_.cc"],
+    deps = ["//:gtest"],
+)
+
+cc_test(
+    name = "gtest_skip_test",
+    size = "small",
+    srcs = ["gtest_skip_test.cc"],
+    deps = ["//:gtest_main"],
+)
+
+cc_test(
+    name = "gtest_skip_in_environment_setup_test",
+    size = "small",
+    srcs = ["gtest_skip_in_environment_setup_test.cc"],
+    deps = ["//:gtest_main"],
+)
+
+py_test(
+    name = "gtest_skip_environment_check_output_test",
+    size = "small",
+    srcs = ["gtest_skip_environment_check_output_test.py"],
+    data = [
+        ":gtest_skip_in_environment_setup_test",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+py_test(
+    name = "googletest-list-tests-unittest",
+    size = "small",
+    srcs = ["googletest-list-tests-unittest.py"],
+    data = [":googletest-list-tests-unittest_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-shuffle-test_",
+    srcs = ["googletest-shuffle-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-shuffle-test",
+    size = "small",
+    srcs = ["googletest-shuffle-test.py"],
+    data = [":googletest-shuffle-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-catch-exceptions-no-ex-test_",
+    testonly = 1,
+    srcs = ["googletest-catch-exceptions-test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+cc_binary(
+    name = "googletest-catch-exceptions-ex-test_",
+    testonly = 1,
+    srcs = ["googletest-catch-exceptions-test_.cc"],
+    copts = ["-fexceptions"],
+    deps = ["//:gtest_main"],
+)
+
+py_test(
+    name = "googletest-catch-exceptions-test",
+    size = "small",
+    srcs = ["googletest-catch-exceptions-test.py"],
+    data = [
+        ":googletest-catch-exceptions-ex-test_",
+        ":googletest-catch-exceptions-no-ex-test_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "gtest_xml_output_unittest_",
+    testonly = 1,
+    srcs = ["gtest_xml_output_unittest_.cc"],
+    deps = ["//:gtest"],
+)
+
+cc_test(
+    name = "gtest_no_test_unittest",
+    size = "small",
+    srcs = ["gtest_no_test_unittest.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "gtest_xml_output_unittest",
+    size = "small",
+    srcs = [
+        "gtest_xml_output_unittest.py",
+        "gtest_xml_test_utils.py",
+    ],
+    args = select({
+        "//:has_absl": [],
+        "//conditions:default": ["--no_stacktrace_support"],
+    }),
+    data = [
+        # We invoke gtest_no_test_unittest to verify the XML output
+        # when the test program contains no test definition.
+        ":gtest_no_test_unittest",
+        ":gtest_xml_output_unittest_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "gtest_xml_outfile1_test_",
+    testonly = 1,
+    srcs = ["gtest_xml_outfile1_test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+cc_binary(
+    name = "gtest_xml_outfile2_test_",
+    testonly = 1,
+    srcs = ["gtest_xml_outfile2_test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+py_test(
+    name = "gtest_xml_outfiles_test",
+    size = "small",
+    srcs = [
+        "gtest_xml_outfiles_test.py",
+        "gtest_xml_test_utils.py",
+    ],
+    data = [
+        ":gtest_xml_outfile1_test_",
+        ":gtest_xml_outfile2_test_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "googletest-uninitialized-test_",
+    testonly = 1,
+    srcs = ["googletest-uninitialized-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-uninitialized-test",
+    size = "medium",
+    srcs = ["googletest-uninitialized-test.py"],
+    data = ["googletest-uninitialized-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+cc_binary(
+    name = "gtest_testbridge_test_",
+    testonly = 1,
+    srcs = ["gtest_testbridge_test_.cc"],
+    deps = ["//:gtest_main"],
+)
+
+# Tests that filtering via testbridge works
+py_test(
+    name = "gtest_testbridge_test",
+    size = "small",
+    srcs = ["gtest_testbridge_test.py"],
+    data = [":gtest_testbridge_test_"],
+    deps = [":gtest_test_utils"],
+)
+
+py_test(
+    name = "googletest-json-outfiles-test",
+    size = "small",
+    srcs = [
+        "googletest-json-outfiles-test.py",
+        "gtest_json_test_utils.py",
+    ],
+    data = [
+        ":gtest_xml_outfile1_test_",
+        ":gtest_xml_outfile2_test_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+py_test(
+    name = "googletest-json-output-unittest",
+    size = "medium",
+    srcs = [
+        "googletest-json-output-unittest.py",
+        "gtest_json_test_utils.py",
+    ],
+    args = select({
+        "//:has_absl": [],
+        "//conditions:default": ["--no_stacktrace_support"],
+    }),
+    data = [
+        # We invoke gtest_no_test_unittest to verify the JSON output
+        # when the test program contains no test definition.
+        ":gtest_no_test_unittest",
+        ":gtest_xml_output_unittest_",
+    ],
+    deps = [":gtest_test_utils"],
+)
+
+# Verifies interaction of death tests and exceptions.
+cc_test(
+    name = "googletest-death-test_ex_catch_test",
+    size = "medium",
+    srcs = ["googletest-death-test_ex_test.cc"],
+    copts = ["-fexceptions"],
+    defines = ["GTEST_ENABLE_CATCH_EXCEPTIONS_=1"],
+    deps = ["//:gtest"],
+)
+
+cc_binary(
+    name = "googletest-param-test-invalid-name1-test_",
+    testonly = 1,
+    srcs = ["googletest-param-test-invalid-name1-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+cc_binary(
+    name = "googletest-param-test-invalid-name2-test_",
+    testonly = 1,
+    srcs = ["googletest-param-test-invalid-name2-test_.cc"],
+    deps = ["//:gtest"],
+)
+
+py_test(
+    name = "googletest-param-test-invalid-name1-test",
+    size = "small",
+    srcs = ["googletest-param-test-invalid-name1-test.py"],
+    data = [":googletest-param-test-invalid-name1-test_"],
+    deps = [":gtest_test_utils"],
+)
+
+py_test(
+    name = "googletest-param-test-invalid-name2-test",
+    size = "small",
+    srcs = ["googletest-param-test-invalid-name2-test.py"],
+    data = [":googletest-param-test-invalid-name2-test_"],
+    deps = [":gtest_test_utils"],
+)