利用“宏元编程”解决重复问题

本文介绍了如何通过宏元编程技术解决配置数据在不同结构中重复的问题。通过定义元数据并创建一系列宏,实现了配置信息的自动生成功能,简化了StudentConfig和StudentOptionalConfig结构的定义,并给出了一个简单的Python代码生成器示例。
摘要由CSDN通过智能技术生成
在一个网元中,存在着各种“受管对象”(Managed Object)。每种“受管对象”都有自己的一组配置数据。比如,一个“学生”对象的配置数据定义如下:
struct Student
{
   unsigned long  code;
   char           name[9];
   unsigned char  height;
   unsigned short score;
};
在“受管对象”配置修改的过程中,如果出了差错,应该可以将配置“回滚”到之前的值。所以,我们定义了如下模版来保存一个配置项。
template <typename T>
struct ConfigValue
{
   ConfigValue(const T& defaultValue)
      : changed(false) 
      , currentValue(defaultValue)
      , oldValue(defaultValue)
      {}

   void set(const T& value)
   {
      if(currentValue == value) return;

      oldValue = currentValue;
      currentValue = value;
      changed = true;
   }

   const T& get() const
   { return currentValue; }

   const T& getOldValue() const
   { return changed ? oldValue : currentValue; }

   void resetStatus()
   { changed = false; }

   void revert()
   {
      if(not changed) return;

      currentValue = oldValue;
      changed = false;
   }

   bool isChanged() const
   { return changed; }

private:
   bool changed;
   T    currentValue;
   T    oldValue;
};
基于此模版,我们将“学生”的配置定义为:
struct StudentConfig
{
   ConfigValue<unsigned long>       code;
   ConfigValue<FixedSizeString<8> > name;
   ConfigValue<unsigned char>       height;
   ConfigValue<unsigned short>      score;
};
通过SNMP的客户端,用户可以一次性修改某个“受管对象”的多个配置数据。比如,对于某个“学生”对象,用户可以同时修改他的“身高”和“总成绩”。所以我们定义了如下模版来保存由SNMP客户端而来的某个配置项:
template <typename T>
struct OptionalConfigValue
{
   OptionalConfigValue() : specified(false) {}

   void set(const T& value)
   {
      this->value = value;
      specified   = true;
   }

   void updateTo(ConfigValue<T>& config) const
   {
      if(specified) config.set(value);
   }

private:
   bool specified;
   T    value;
};
以“学生”对象为例,相应的SNMP配置结构则定义为:
struct StudentOptionalConfig
{
   OptionalConfigValue<unsigned long>       code;
   OptionalConfigValue<FixedSizeString<8> > name;
   OptionalConfigValue<unsigned char>       height;
   OptionalConfigValue<unsigned short>      score;
};
这样,StudentConfig应该提供一个update接口,来更新来自于SNMP客户端的配置数据。比如:
struct StudentConfig
{
   StudentConfig()
      : code(0)
      , name("anon")
      , height(170)
      , score(0)
   {}

   void update(const StudentOptionalConfig& config)
   {
      config.code.updateTo(code);
      config.name.updateTo(name);
      config.height.updateTo(height);
      config.score.updateTo(score);
   }

   void revert()
   {
      code.revert();
      name.revert();
      height.revert();
      score.revert();
   }

   void configDone()
   {
      code.resetStatus();
      name.resetStatus();
      height.resetStatus();
      score.resetStatus(); 
   }

private:
   ConfigValue<unsigned long>       code;
   ConfigValue<FixedSizeString<8> > name;
   ConfigValue<unsigned char>       height;
   ConfigValue<unsigned short>      score;
};
从上述的实现中,我们能够发现强烈的重复模式:首先,所有的配置信息在不同的地方重复出现,其次,对于不同的配置信息进行相同的处理。

为了解决这样的重复问题,我们首先使用宏来定义“元数据”:
// Student.h

DEFINE_CONFIG    (code,     unsigned long,  0)
DEFINE_CONFIG    (height,   unsigned char,  170)
DEFINE_CONFIG    (score,    unsigned short, 0)
DEFINE_STR_CONFIG(name,     8,              "anon")
而“魔法”的关键在于,如何来通过不同的宏定义来“解释”这些元数据。
比如,对于StudentOptionalConfig的定义,我们可以将其代码转化为:
// StudentOptionalConfig.h

struct StudentOptionalConfig
{
#include <OptionalConfigDef.h>
#include "Student.h"
};
而OptionalConfig.h的定义为:
// OptionalConfigDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   OptionalConfigValue<type> name;


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   OptionalConfigValue<FixedSizeString<size> > name;
类似的,StudentConfig的定义则变为:
// StudentConfig.h

struct StudentConfig
{
   StudentConfig() : 
   #include <DefaultValueDef.h>
   #include "Student.h"
   , dummy(true)
   {}

   void update(const StudentOptionalConfig& config)
   {
      #include <UpdateDef.h>
      #include "Student.h"
   }

   void revert()
   {
      #include <RevertDef.h>
      #include "Student.h"
   }

   void configDone()
   {
      #include <ConfigDoneDef.h>
      #include "Student.h"
   }

private:
   #include <ConfigDef.h>
   #include "Student.h"

   bool dummy;
};
而各个魔法头文件的定义分别为:
// DefaultValueDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   name(defaultValue),


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   name(defaultValue),
// UpdateDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   config.name.updateTo(name);


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   config.name.updateTo(name);
// CofigDoneDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   name.resetStatus();


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   name.resetStatus();
// RevertDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   name.revert();


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   name.revert();
// ConfigDef.h


#ifdef DEFINE_CONFIG
#undef DEFINE_CONFIG
#endif

#define DEFINE_CONFIG(name, type, defaultValue) \
   ConfigValue<type> name;


#ifdef DEFINE_STR_CONFIG
#undef DEFINE_STR_CONFIG
#endif

#define DEFINE_STR_CONFIG(name, size, defaultValue) \
   ConfigValue<FixedSizeString<size> > name;
有了这些魔法定义文件,每个配置定义文件就呈现除了简单一致的规则,很容易就可以写出一个代码生成器,自动生成相关的代码。下面是一个Python的实现:
import sys

optional_config_template = '''
#ifndef __%s_OPTIONAL_CONFIG_H__
#define __%s_OPTIONAL_CONFIG_H__

struct %sOptionalConfig
{
   #include <OptionalConfigDef.h>
   #include "%s.h"   
};

#endif
'''


config_template = '''

#ifndef __%s_CONFIG_H__
#define __%s_CONFIG_H__

struct %sConfig
{
   %sConfig()
   #include <DefaultValueDef.h>
   #include "%s.h"
   dummy(true)
   {}

   void update(const %sOptionalConfig& config)
   {
      #include <UpdateDef.h>
      #include "%s.h"
   }

   void configDone()
   {
      #include <ConfigDoneDef.h>
      #include "%s.h"
   }

   void revert()
   {
      #include <RevertDef.h>
      #include "%s.h"
   }

private:
   #include <ConfigDef.h>
   #include "%s.h"   

   bool dummy;
};

#endif
'''

def write_file(name, suffix, content) :
   file = open(name + suffix + ".h", "w")
   file.write(content)
   file.close()

def generate_optional_config(name) :
   write_file(name, "OptionalConfig", \
      optional_config_template % \
          ( name.upper(), name.upper(), name, name))

def generate_config(name) :
   write_file(name, "Config", \
      config_template % \
          ( name.upper(), name.upper() \
          , name, name, name, name, name, name, name, name))

def generate(name) :
   generate_optional_config(name)
   generate_config(name)

def usage() :
   print "usage: python config-gen.py config-name"

if __name__ == "__main__":
   if len(sys.argv) != 2:
      usage()
      sys.exit(1)

   generate(sys.argv[1])

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值