#Command control mode of C + + nine Yin Scripture

The so-called command control mode is to encapsulate the corresponding behavior. Through the command, you can control it. You can understand it as the instruction operation under linux.
   For example, an operation includes 10 steps of A1, A2, and... A10. If one step fails, it will be rewound. If the business types of these 10 operations are different and the parameters required are different, it will be difficult to operate. If I can encapsulate all of them into instruction mode and trigger them only through 10 strings of A1 to A10, then the implementation starts It's much easier to come.
For network programming, command control becomes essential. This model can help you manage the network layer and business layer perfectly.
    
 
Implementation constraints:
1. I need to divide each type of business into one business entry class for unified management.
2. I have many kinds of business. In order to facilitate the expansion, I need to change the framework content as little as possible for each business class added.
3. I can define the function of each business entry class as a command.
4. Each command word allows me to pass in different parameter lists
 
 
Based on the above constraints, it may be a little difficult to implement, so we will sort it out in two steps:
 
Step 1: management and implementation of business entry class
Implementation principle:
1. When static members of template class are called, the compiler will automatically expand them.
2. Static members will be initialized before the main function
3. In each business entry class, define a specified static function, and use the template class in the function, so that the compiler can generate template class instances;
4. The static member of the template class is initialized to the static function address of the business class.
5. When initializing static members, make a link list between template classes
 
Based on the above principles, we can implement a relationship between the parent class and the child class as shown in the following figure:
Step 2: summarize the command words of all containers
This is relatively simple, directly traverse the container, execute all the container functions, and summarize the command words.
 
Code implementation:
. h file:
#include <map>
#include <string>
#include <iostream>
#include <unordered_map>
#include <memory>
#include <functional>
#include "singleton.h"
#include "anyval.h"


#define BEGINE_OPCODEREG(className) public:
     static void OpcodeInit() {
        COPHandleContainer<className> handle;

#define DEFINE_OPCODE(opcode, funcAddr) MakeFuncEntityNode(funcAddr, opcode, #funcAddr);

#define END_OPCODEREG() } private:


//Command word distribution class
class COpcodeDispatch
{
public:
	~COpcodeDispatch(void) {};

    void Initialize();

	void RegisterOpcode(const char* opcode, AnyVar opProc, AnyVar funcName);

	//Command word distribution
    template<typename... ARGS>
	void Dispatch(const std::string& opcode, ARGS... args)
    {
        auto iter = m_opHandle.find(opcode);
		if (m_opHandle.end() == iter)
		{
			return ;
		}

		AnyVar resolver = iter->second;
		std::function<void (ARGS...)> funcPtr = any_cast<std::function<void (ARGS...)>>(resolver);

		funcPtr(args...);
    }


    void Dump();
private:
	std::unordered_map<std::string, AnyVar> m_opHandle;
    std::unordered_map<std::string, AnyVar> m_opFuncName;
	
};

typedef Singleton<COpcodeDispatch> COpcodeDispatchAgent;



//This class is used to store information of all command byte points, including function address and function name
template <typename T, typename... ARGS>
class CMemFuncEntityNode 
{
public:
	typedef void (T::*mem_func_type)(ARGS...);
	CMemFuncEntityNode(mem_func_type memFunc, const char* memFuncName) :m_memFuncAddr(memFunc), m_memFuncName(memFuncName) {}
	void operator()(ARGS...args)
	{
		T obj;
		(obj.*m_memFuncAddr)(args...);
	}

	//Classes supporting Opcode, native support for dynamic creation
	void* DynCreate()
	{
		return new T;
	}

	const char* GetMemFuncName()
	{
		return m_memFuncName[0] == '&' ? m_memFuncName + 1 : m_memFuncName;
	}
private:
	mem_func_type m_memFuncAddr;
	const char* m_memFuncName;
};

template<typename T, typename... ARGS>
void MakeFuncEntityNode(void (T::*mem_func_type)(ARGS...), const char* opcode, const char* memFuncName)
{
    auto opNode = std::make_shared<CMemFuncEntityNode<T, ARGS...>>(mem_func_type, memFuncName);

	//Unified conversion to void (ARGS...) function, wrapped with anyval
    std::function<void (ARGS...)> function = [opNode](ARGS... args) {
       (*opNode)(args...);
    };

    std::function<const char* ()> funcName = [opNode]() {
        return opNode->GetMemFuncName();
    };

	COpcodeDispatchAgent::get_instance().RegisterOpcode(opcode, function, funcName);
}

//Container base class, which stores all node information and container node information
class COPContainerBase
{
public:
	static void Initialize();
protected:
	typedef void(*cont_func_type)();
	

	virtual ~COPContainerBase();

	//Storage container node, return to container header node
	static COPContainerBase*& Head();
	

	
	//This function is a virtual function. The purpose is for the compiler to check the class that inherits the class and implements the function
	virtual void DoNothing()const;
	
protected:
	cont_func_type m_containtFunc;
	COPContainerBase* m_nextContainer;

};

//Container class
template <typename T>
class COPHandleContainer : public COPContainerBase
{
public:
	COPHandleContainer(void)
	{
	}
	
	static COPHandleContainer* GetInstance()
	{
		//Note: This is a single example. If it is called multiple times, the Head() linked list will enter the forming cycle
		static COPHandleContainer<T> containerIns;
		return &containerIns;
	}
	//This function is a virtual function, which will be checked by the compiler, so as to realize the purpose of referencing static variables
	//All classes instantiating the template class will initialize the static variable, so you must implement the T::OpcodeInit static function
	inline void DoNothing()const
	{
		m_opInstance.DoNothing();
	}

private:

	struct ContaintInstance
	{
		ContaintInstance(cont_func_type containtFunc)
		{
#ifdef _DEBUG
			std::cout << "Initialize container functions" << std::endl;
#endif
			COPHandleContainer *container = COPHandleContainer::GetInstance();
			container->m_containtFunc = containtFunc;
			container->m_nextContainer = Head();
			Head() = container;
		}
		inline void DoNothing()const {}
	};

	static ContaintInstance m_opInstance;
};

//opcode container loading
template < typename T >
typename COPHandleContainer<T>::ContaintInstance COPHandleContainer<T>::m_opInstance(T::OpcodeInit);

. cpp file

#include "opcodedispatch.h"


void COpcodeDispatch::RegisterOpcode(const char* opcode, AnyVar opProc, AnyVar funcName)
{
    if (m_opHandle.end() != m_opHandle.find(opcode))
    {
        throw std::invalid_argument(std::string(opcode) + " : this opcode has already exist!");
    } 
    else
    {
        m_opHandle.emplace(opcode, opProc);
        m_opFuncName.emplace(opcode, funcName);
    }
}


void COpcodeDispatch::Initialize()
{
    COPContainerBase::Initialize();
}

void COpcodeDispatch::Dump()
{
    for(auto item : m_opFuncName)
    {
        AnyVar resolver = item.second;
		std::function<const char* ()> funcPtr = any_cast<std::function<const char* ()>>(resolver);

		std::cout << item.first << "-->" << funcPtr() << std::endl;;
    }
}

/*********************************************************

COPContainerBase

***********************************************************/

COPContainerBase::~COPContainerBase()
{

}

//Storage container node, return to container header node
COPContainerBase*& COPContainerBase::Head()
{
	static COPContainerBase *containerHead = 0;
	return containerHead;
}



void COPContainerBase::Initialize()
{
	//Initialize container
	COPContainerBase* currContainer = Head();
	while (currContainer != NULL)
	{
		(*currContainer->m_containtFunc)();
		currContainer = currContainer->m_nextContainer;
	}
}

//This function is a virtual function. The purpose is for the compiler to check the class that inherits the class and implements the function
void COPContainerBase::DoNothing()const
{
}

Test code:

class TestOpcode
{
BEGINE_OPCODEREG(TestOpcode)
    DEFINE_OPCODE("TestFunc", &TestOpcode::Func)
    DEFINE_OPCODE("TestFunc2", &TestOpcode::Func2)
END_OPCODEREG()
public:
	void Func()
	{
		std::cout << "TestOpcode Func" << std::endl;
	}

    void Func2(int a, int b)
	{
		std::cout << "TestOpcode func2:" << a*b << std::endl;
	}
};

int main()
{
	COpcodeDispatchAgent::get_instance().Initialize();

    COpcodeDispatchAgent::get_instance().Dump();
	COpcodeDispatchAgent::get_instance().Dispatch("TestFunc");

    COpcodeDispatchAgent::get_instance().Dispatch("TestFunc2", 10, 20);
    return 0;
}
Output:
TestFunc2-->TestOpcode::Func2
TestFunc-->TestOpcode::Func
TestOpcode Func
TestOpcode func2:200

Tags: Programming network Linux

Posted on Tue, 26 May 2020 20:54:36 -0700 by rooky