Обертка вокруг TLV-скаляров

Опыт применения первой реализации классов oess_1::tlv::scalar_tlv_t и oess_1::tlv::basic_string_tlv_t в виде элементов составного TLV (oess_1::tlv::compound_tlv_t) привел к появлению класса oess_1::tlv::tagged_scalar_wrapper_t. Ниже описываются причины его появления и то, как этот класс может упростить программирование составных TLV.

Проблема

Предположим, что требуется представить в TLV запрос user_req и ответ на запрос user_reply, которые описываются следующими C++ структурами:

struct  user_req_t
{
  // Идентификатор запроса.
  unsigned int  m_rid;
  // Имя пользователя.
  std::string m_user_name;
  // Текст запроса.
  std::string m_req_body;
};

struct  user_reply_t
{
  // Идентификатор запроса.
  unsigned int  m_rid;
  // Имя пользователя.
  std::string m_user_name;
  // Результат обработки.
  unsigned int  m_result;
};

В виде TLV эти сообщения могут быть представлены в следующем виде:

user-req-tlv
	rid-tlv
	user-name-tlv
	req-body-tlv

user-reply-tlv
	rid-tlv
	user-name-tlv
	result-tlv

Т.е. rid и user-name представляются одними и теми же TLV как в user-req-tlv, так и в user-reply-tlv.

При тривиальном программировании TLV-объектов был бы получен следующий код:

class user_req_tlv_t :
  public oess_1::tlv::compound_tlv_t
{
  typedef oess_1::tlv::compound_tlv_t base_type_t;

  private :
    // Для rid-tlv.
    oess_1::tlv::scalar_tlv_t< oess_1::uint_t, oess_1::uint_t >
      m_rid_tlv;
    // Для user-name-tlv.
    oess_1::tlv::basic_string_tlv_t< oess_1::uint_t >
      m_user_name_tlv;
    // Для req-body-tlv.
    oess_1::tlv::basic_string_tlv_t< oess_1::uint_t >
      m_req_body_tlv;
  public :
    user_req_tlv_t()
      :
        base_type_t( c_user_req_tag ),
        m_rid_tlv( c_rid_tag ),
        m_user_name_tlv( c_user_name_tag ),
        m_req_body_tlv( c_req_body_tag )
    {
      tlv_add( m_rid_tlv );
      tlv_add( m_user_name_tlv );
      tlv_add( m_req_body_tlv );
    }
    ...
};

class user_reply_tlv_t :
  public oess_1::tlv::compound_tlv_t
{
  typedef oess_1::tlv::compound_tlv_t base_type_t;

  private :
    // Для rid-tlv.
    oess_1::tlv::scalar_tlv_t< oess_1::uint_t, oess_1::uint_t >
      m_rid_tlv;
    // Для user-name-tlv.
    oess_1::tlv::basic_string_tlv_t< oess_1::uint_t >
      m_user_name_tlv;
    // Для result-tlv.
    oess_1::tlv::scalar_tlv_t< oess_1::uint_t, oess_1::uint_t >
      m_result_tlv;
  public :
    user_reply_tlv_t()
      :
        base_type_t( c_user_reply_tag ),
        m_rid_tlv( c_rid_tag ),
        m_user_name_tlv( c_user_name_tag ),
        m_result_tlv( c_result_tag )
    {
      tlv_add( m_rid_tlv );
      tlv_add( m_user_name_tlv );
      tlv_add( m_result_tlv );
    }
    ...
};

Проблема заключается в том, что поля m_rid_tlv и m_user_name_tlv должны связываться с константами c_rid_tag, c_user_name_tag в каждом (!) конструкторе классов user_req_tlv_t и user_reply_tlv_t. В нормальном варианте, в каждом из классов должно быть три конструктора: по умолчанию, со всеми параметрами и копирования. Т.е. в нормальном варианте классов user_req_tlv_t и user_reply_tlv_t придется указывать константы c_rid_tag и c_user_name_tag 6 раз! Хуже всего, что короме затрат времени на написание вызовов конструкторов m_rid_tlv и m_user_name_tlv, в дальнейшем может потребоваться заменить для какого-то поля значение Tag. Тогда в исходном тексте окажется много мест, в которые нужно внести изменения. А это повышает вероятность появления ошибок.

Решение

Решение состоит в том, что посредством класса oess_1::tlv::tagged_scalar_wrapper_t описывается тип, связывающий конкретный Tag с типом обработчика скалярного Value:

// Тип для rid-tlv.
typedef oess_1::tlv::tagged_scalar_wrapper_t<
    c_rid_tag,
    oess_1::tlv::scalar_tlv_t< oess_1::uint_t, oess_1::uint_t > >
  rid_tlv_t;

// Тип для user-name-tlv.
typedef oess_1::tlv::tagged_scalar_wrapper_t<
    c_user_name_tag,
    oess_1::tlv::basic_string_tlv_t< oess_1::uint_t > >
  user_name_tlv_t;

// Тип для req-body-tlv.
typedef oess_1::tlv::tagged_scalar_wrapper_t<
    c_req_body_tag,
    oess_1::tlv::basic_string_tlv_t< oess_1::uint_t > >
  req_body_tlv_t;

// Тип для result-tlv.
typedef oess_1::tlv::tagged_scalar_wrapper_t<
    c_result_tag,
    oess_1::tlv::scalar_tlv_t< oess_1::uint_t, oess_1::uint_t > >
  result_tlv_t;

class user_req_tlv_t :
  public oess_1::tlv::compound_tlv_t
{
  typedef oess_1::tlv::compound_tlv_t base_type_t;

  private :
    // Для rid-tlv.
    rid_tlv_t m_rid_tlv;
    // Для user-name-tlv.
    user_name_tlv_t m_user_name_tlv;
    // Для req-body-tlv.
    req_body_tlv_t  m_req_body_tlv;
  public :
    user_req_tlv_t()
      :
        base_type_t( c_user_req_tag )
    {
      tlv_add( m_rid_tlv );
      tlv_add( m_user_name_tlv );
      tlv_add( m_req_body_tlv );
    }
    ...
};

class user_reply_tlv_t :
  public oess_1::tlv::compound_tlv_t
{
  typedef oess_1::tlv::compound_tlv_t base_type_t;

  private :
    // Для rid-tlv.
    rid_tlv_t m_rid_tlv;
    // Для user-name-tlv.
    user_name_tlv_t m_user_name_tlv;
    // Для result-tlv.
    result_tlv_t  m_result_tlv;
  public :
    user_reply_tlv_t()
      :
        base_type_t( c_user_reply_tag )
    {
      tlv_add( m_rid_tlv );
      tlv_add( m_user_name_tlv );
      tlv_add( m_result_tlv );
    }
    ...
};

Документация по ObjESSty. Последние изменения: Fri Oct 13 18:35:37 2006. Создано системой  doxygen 1.4.7
Hosted by uCoz